1. Libraries and functions

1.1 Libraries

Load the required libraries.

library(tidyverse)
library(sf)
library(here)
library(readxl)
library(scales)
library(DT)
library(brms)
library(tidybayes)
library(patchwork)
library(marginaleffects)
library(ggrepel)
library(scico)
library(ggdensity)
library(ggpubr)
library(units)
#library(ggsn)

1.2 Helper functions

Functions that we will use throughout the script

#labeller for years
year_labels <- c(1950:1963)

#The Glasgow mass minuture chest X-ray campaign happened between 11th March and 12th April 1957
#Segment for graphs to match ACF period
acf_start <- decimal_date(ymd("1957-03-11"))
acf_end <- decimal_date(ymd("1957-04-12"))

Function for counterfactual plots



plot_counterfactual <- function(model_data, model, population_denominator, outcome, grouping_var=NULL, re_formula,...){
  
  #labeller for years
  year_labels <- c(1950:1963)

  #The Glasgow mass minuture chest X-ray campaign happened between 11th March and 12th April 1957
  #Segment for graphs to match ACF period
  acf_start <- decimal_date(ymd("1957-03-11"))
  acf_end <- decimal_date(ymd("1957-04-12"))

  summary <- {{model_data}} %>%
    select(year, year2, y_num, acf_period, {{population_denominator}}, {{outcome}}, {{grouping_var}}) %>%
    add_epred_draws({{model}}, re_formula={{re_formula}}) %>%
    group_by(year2, acf_period, {{grouping_var}}) %>%
    mean_qi() %>%
    mutate(.epred_inc = .epred/{{population_denominator}}*100000,
          .epred_inc.lower = .epred.lower/{{population_denominator}}*100000,
          .epred_inc.upper = .epred.upper/{{population_denominator}}*100000) %>%
    mutate(acf_period = case_when(acf_period=="a. pre-acf" ~ "Before Intervention",
                                  acf_period=="c. post-acf" ~ "Post Intervention"))



  #create the counterfactual (no intervention), and summarise
  
  counterfact <-
    add_epred_draws(object = {{model}},
                    newdata = {{model_data}} %>%
                                  select(year, year2, y_num, {{population_denominator}}, {{grouping_var}}, {{outcome}}) %>%
                                  mutate(acf_period = "a. pre-acf"), re_formula={{re_formula}}) %>%
    group_by(year2, acf_period, {{grouping_var}}) %>%
    mean_qi() %>%
    mutate(.epred_inc = .epred/{{population_denominator}}*100000,
         .epred_inc.lower = .epred.lower/{{population_denominator}}*100000,
         .epred_inc.upper = .epred.upper/{{population_denominator}}*100000) %>%
    mutate(acf_period = case_when(acf_period=="a. pre-acf" ~ "Before Intervention",
                                acf_period=="c. post-acf" ~ "Post Intervention"))
  


  #plot the intervention effect
p <- summary %>%
    droplevels() %>%
    ggplot() +
    geom_ribbon(aes(ymin=.epred_inc.lower, ymax=.epred_inc.upper, x=year2, group = acf_period, fill=acf_period), alpha=0.5) +
    geom_ribbon(data = counterfact %>% filter(year>=1956), 
                aes(ymin=.epred_inc.lower, ymax=.epred_inc.upper, x=year2, fill="Counterfactual"), alpha=0.5) +
    geom_line(data = counterfact %>% filter(year>=1956), 
              aes(y=.epred_inc, x=year2, colour="Counterfactual")) +
    geom_line(aes(y=.epred_inc, x=year2, group=acf_period,  colour=acf_period)) +
    geom_point(data = {{model_data}}, aes(y={{outcome}}, x=year2, shape=acf_period), size=2) +
    geom_vline(aes(xintercept=acf_end), linetype=3) +
    theme_ggdist() +
    scale_y_continuous(labels=comma, limits = c(0,NA)) +
    scale_x_continuous(labels = year_labels,
                       breaks = year_labels) +
    scale_fill_manual(values = c("#DE0D92", "grey50", "#4D6CFA") , name="", na.translate = F) +
    scale_colour_manual(values = c("#DE0D92", "grey50", "#4D6CFA") , name="", na.translate = F) +
    scale_shape_discrete(name="", na.translate = F) +
    labs(
      x = "Year",
      y = "Case notification rate (per 100,000)",
      caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)"
    ) +
    theme(legend.position = "bottom",
          panel.border = element_rect(colour = "grey78", fill=NA),
          text = element_text(size=8),
          axis.text.x = element_text(size=8, angle = 90, hjust=1, vjust=0.5),
          legend.text = element_text(size=8)) +
    guides(shape="none")

    facet_vars <- vars(...)

  if (length(facet_vars) != 0) {
    p <- p + facet_wrap(facet_vars)
  }
  p

}

Function for calculating measures of change over time (RR.peak, RR.level, RR.slope)


summarise_change <- function(model_data, model, population_denominator, grouping_var = NULL, re_formula = NULL) {
  
  #functions for calculating RR.peak
  #i.e. relative case notification rate in 1957 vs. counterfactual trend for 1957
  
  grouping_var <- enquo(grouping_var)
  
  if (!is.null({{grouping_var}})) {
    
    #make the prediction matrix, conditional on whether we want random effects included or not.
    out <- crossing({{model_data}} %>% 
                      select({{population_denominator}}, y_num, !!grouping_var) %>%
                      filter(y_num == 8),
                    acf_period = c("a. pre-acf", "b. acf")
    )
  } else {
    
    out <- crossing({{model_data}} %>% 
                      select({{population_denominator}}, y_num) %>%
                      filter(y_num == 8),
                    acf_period = c("a. pre-acf", "b. acf")
    )
  }
  
  peak_draws <- add_epred_draws(newdata = out,
                  object = {{model}},
                  re_formula = {{re_formula}}) %>%
    mutate(epred_cnr = .epred/population_without_inst_ship*100000) %>%
    group_by(.draw, !!grouping_var) %>%
    summarise(estimate = last(epred_cnr)/first(epred_cnr)) %>%
    ungroup() %>%
    mutate(measure = "RR.peak")
  
  peak_summary <- peak_draws %>%
    group_by(!!grouping_var) %>%
    mean_qi(estimate) %>%
    mutate(measure = "RR.peak")
  
  
  #functions for calculating RR.step
  #i.e. relative case notification rate in 1958 vs. counterfactual trend for 1958
  
    if (!is.null({{grouping_var}})) {
    out2 <- crossing({{model_data}} %>% 
                      select({{population_denominator}}, y_num, !!grouping_var) %>%
                      filter(y_num == 9),
                    acf_period = c("a. pre-acf", "c. post-acf")
    )
  } else {
    
    out2 <- crossing({{model_data}} %>% 
                      select({{population_denominator}}, y_num) %>%
                      filter(y_num == 9),
                    acf_period = c("a. pre-acf", "c. post-acf")
    )
  }
  
    level_draws <- add_epred_draws(newdata = out2,
                  object = {{model}},
                  re_formula = {{re_formula}}) %>%
    arrange(y_num, .draw) %>%
    mutate(epred_cnr = .epred/population_without_inst_ship*100000) %>%
    group_by(.draw, !!grouping_var) %>%
    summarise(estimate = last(epred_cnr)/first(epred_cnr)) %>%
    ungroup() %>%
    mutate(measure = "RR.level")
  
  level_summary <- level_draws %>%
    group_by(!!grouping_var) %>%
    mean_qi(estimate) %>%
    mutate(measure = "RR.level")
    
    
  #functions for calculating RR.slope
  #i.e. relative change in case notification rate in 1958-1963 vs. counterfactual trend for 1959-1963
  
    if (!is.null({{grouping_var}})) {
    out3 <- crossing({{model_data}} %>% 
                      select({{population_denominator}}, y_num, !!grouping_var) %>%
                      filter(y_num %in% c(9,14)),
                    acf_period = c("a. pre-acf", "c. post-acf")
    )
  } else {
    
    out3 <- crossing({{model_data}} %>% 
                      select({{population_denominator}}, y_num) %>%
                      filter(y_num %in% c(9,14)),
                    acf_period = c("a. pre-acf", "c. post-acf")
    )
  }
  
    slope_draws <- add_epred_draws(newdata = out3,
                  object = {{model}},
                  re_formula = {{re_formula}}) %>%
        arrange(y_num) %>%
        ungroup() %>%
        mutate(epred_cnr = .epred/population_without_inst_ship*100000) %>%
        group_by(.draw, acf_period, !!grouping_var) %>%
        summarise(slope = (last(epred_cnr) - first(epred_cnr)) / (last(y_num)-first(y_num))) %>%
        ungroup() %>%
        group_by(.draw, !!grouping_var) %>%
        summarise(estimate = last(slope)/first(slope)) %>%
        mutate(measure = "RR.slope")
  
  slope_summary <- slope_draws %>%
     group_by(!!grouping_var) %>%
      median_qi(estimate) %>%
      mutate(measure = "RR.slope")
    
  #gather all the results into a named list
    lst(peak_draws=peak_draws, peak_summary=peak_summary, 
        level_draws=level_draws, level_summary=level_summary, 
        slope_draws=slope_draws, slope_summary=slope_summary)
  
}

Function for calculating difference from counterfactual


calculate_counterfactual <- function(model_data, model, population_denominator, grouping_var=NULL, re_formula=NA){
  
  #effect vs. counterfactual
  counterfact <-
      add_epred_draws(object = {{model}},
                      newdata = {{model_data}} %>%
                                    select(year, year2, y_num, {{population_denominator}}, {{grouping_var}}) %>%
                                    mutate(acf_period = "a. pre-acf"),
                      re_formula = {{re_formula}}) %>%
      group_by(.draw, year, {{grouping_var}}, acf_period) %>%
      mutate(.epred_inc_counterf = .epred/{{population_denominator}}*100000, .epred_counterf=.epred)  %>%
      filter(year>1957) %>%
      ungroup() %>%
      select(year, {{population_denominator}}, .draw, .epred_counterf, .epred_inc_counterf, {{grouping_var}})
  
  #Calcuate case notification rate per draw, then summarise.
  post_change <-
      add_epred_draws(object = {{model}},
                      newdata = {{model_data}} %>%
                                    select(year, year2, y_num, {{population_denominator}}, {{grouping_var}}, acf_period),
                      re_formula = {{re_formula}}) %>%
      group_by(.draw, year, {{grouping_var}}, acf_period) %>%
      mutate(.epred_inc = .epred/{{population_denominator}}*100000)  %>%
      filter(year>1957) %>%
      ungroup() %>%
      select(year, {{population_denominator}}, {{grouping_var}}, .draw, .epred, .epred_inc, {{grouping_var}}) 
  
  #for the overall period
    counterfact_overall <-
      add_epred_draws(object = {{model}},
                      newdata = {{model_data}} %>%
                                    select(year, year2, y_num, {{population_denominator}}, {{grouping_var}}) %>%
                                    mutate(acf_period = "a. pre-acf"),
                      re_formula = {{re_formula}}) %>%
      group_by(.draw, {{grouping_var}}) %>%
      filter(year>1957) %>%
      ungroup() %>%
      select({{population_denominator}}, .draw, .epred, {{grouping_var}})  %>%
      group_by(.draw, {{grouping_var}}) %>%
      summarise(.epred_counterf = sum(.epred)) 
  
  #Calcuate case notification rate per draw, then summarise.
  post_change_overall <-
      add_epred_draws(object = {{model}},
                      newdata = {{model_data}} %>%
                                    select(year, year2, y_num, {{population_denominator}}, {{grouping_var}}, acf_period),
                      re_formula = {{re_formula}}) %>%
      group_by(.draw, {{grouping_var}}) %>%
      filter(year>1957) %>%
      ungroup() %>%
      select({{population_denominator}}, {{grouping_var}}, .draw, .epred) %>%
      group_by(.draw, {{grouping_var}}) %>%
      summarise(.epred = sum(.epred)) 
  
  
counter_post <-
  left_join(counterfact, post_change) %>%
    mutate(cases_averted = .epred_counterf-.epred,
           pct_change = (.epred - .epred_counterf)/.epred_counterf,
           diff_inc100k = .epred_inc - .epred_inc_counterf,
           rr_inc100k = .epred_inc/.epred_inc_counterf) %>%
    group_by(year, {{grouping_var}}) %>%
    mean_qi(cases_averted, pct_change, diff_inc100k, rr_inc100k) %>%
    ungroup()

counter_post_overall <-
  left_join(counterfact_overall, post_change_overall) %>%
    mutate(cases_averted = .epred_counterf-.epred,
           pct_change = (.epred - .epred_counterf)/.epred_counterf) %>%
    group_by({{grouping_var}}) %>%
    mean_qi(cases_averted, pct_change) %>%
    ungroup()

lst(counter_post, counter_post_overall)

}

Function for tidying up counterfactuals (mostly for making nice tables)


tidy_counterfactuals <- function(data){
  data %>%
  mutate(across(c(cases_averted:cases_averted.upper, diff_inc100k:diff_inc100k.upper), number_format(accuracy = 0.1, big.mark = ","))) %>%
  mutate(across(c(rr_inc100k:rr_inc100k.upper), number_format(accuracy = 0.01))) %>%
  mutate(across(c(pct_change:pct_change.upper), percent, accuracy=0.1)) %>%
  mutate(year = as.character(year),
            cases_averted = glue::glue("{cases_averted} ({cases_averted.lower} to {cases_averted.upper})"),
            pct_change = glue::glue("{pct_change} ({pct_change.lower} to {pct_change.upper})"),
            diff_inc = glue::glue("{diff_inc100k} ({diff_inc100k.lower} to {diff_inc100k.upper})"),
            rr_inc = glue::glue("{rr_inc100k} ({rr_inc100k.lower} to {rr_inc100k.upper})"))
}


tidy_counterfactuals_overall <- function(data){
  data %>%
  mutate(across(c(cases_averted:cases_averted.upper), number_format(accuracy = 0.1, big.mark = ","))) %>%
  mutate(across(c(pct_change:pct_change.upper), percent, accuracy=0.1)) %>%
  mutate(year = as.character(year),
            cases_averted = glue::glue("{cases_averted} ({cases_averted.lower} to {cases_averted.upper})"),
            pct_change = glue::glue("{pct_change} ({pct_change.lower} to {pct_change.upper})"))
}

2. Data

Import datasets for analysis

2.1 Shapefiles

Make a map of Glasgow wards


glasgow_wards_1951 <- st_read(here("mapping/glasgow_wards_1951.geojson"))
Reading layer `glasgow_wards_1951' from data source 
  `/Users/petermacpherson/Dropbox/Projects/Historical TB ACF 2023-11-28/Work/analysis/glasgow-cxr/mapping/glasgow_wards_1951.geojson' using driver `GeoJSON'
Simple feature collection with 37 features and 3 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: -4.393502 ymin: 55.77464 xmax: -4.070411 ymax: 55.92814
Geodetic CRS:  WGS 84

#read in Scotland boundary
scotland <- st_read(here("mapping/Scotland_boundary/Scotland boundary.shp"))
Reading layer `Scotland boundary' from data source 
  `/Users/petermacpherson/Dropbox/Projects/Historical TB ACF 2023-11-28/Work/analysis/glasgow-cxr/mapping/Scotland_boundary/Scotland boundary.shp' 
  using driver `ESRI Shapefile'
Simple feature collection with 1 feature and 1 field
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: 5513 ymin: 530249 xmax: 470332 ymax: 1220302
Projected CRS: OSGB36 / British National Grid
#make a bounding box for Glasgow
bbox <- st_bbox(glasgow_wards_1951) |> st_as_sfc()

#plot scotland with a bounding box around the City of Glasgow
scotland_with_bbox <- ggplot() +
  geom_sf(data = scotland, fill="antiquewhite") +
  geom_sf(data = bbox, colour = "#C60C30", fill="antiquewhite") +
  theme_void() +
  theme(panel.border = element_rect(colour = "grey78", fill=NA, linewidth = 0.5),
        panel.background = element_rect(fill = "#EAF7FA", size = 0.3))
Warning: The `size` argument of `element_rect()` is deprecated as of ggplot2 3.4.0.
Please use the `linewidth` argument instead.
#plot the wards
#note we tidy up some names to fit on map
glasgow_ward_map <- glasgow_wards_1951 %>%
  mutate(ward = case_when(ward=="Shettleston and Tollcross" ~ "Shettleston and\nTollcross",
                          ward=="Partick (West)" ~ "Partick\n(West)",
                          ward=="Partick (East)" ~ "Partick\n(East)",
                          ward=="North Kelvin" ~ "North\nKelvin",
                          ward=="Kinning Park" ~ "Kinning\nPark",
                          TRUE ~ ward)) %>%
  
  ggplot() +
  geom_sf(aes(fill=division)) +
  geom_sf_label(aes(label = ward), size=3, fill=NA, label.size = NA, colour="black") +
  #scale_colour_identity() +
  scale_fill_brewer(palette = "Set3", name="City of Glasgow Division") +
  theme_grey() +
  labs(x="",
       y="",
       fill="Division") +
  theme(legend.position = "top",
        
        panel.border = element_rect(colour = "grey78", fill=NA, linewidth = 0.5),
        panel.background = element_rect(fill = "antiquewhite", size = 0.3),
        panel.grid.major = element_line(color = "grey78")) +
  guides(fill=guide_legend(title.position = "top", title.hjust = 0.5, title.theme = element_text(face="bold")))

#add the map of scotland as an inset
glasgow_ward_map + inset_element(scotland_with_bbox, 0.75, 0, 1, 0.4)

ggsave(here("figures/s1.png"), height=10, width = 12)

NA
NA

Calculate areas per geographical unit

sf_use_s2(FALSE) #https://github.com/r-spatial/sf/issues/1762
Spherical geometry (s2) switched off
glasgow_wards_1951 <- glasgow_wards_1951 %>%
  mutate(area = st_area(glasgow_wards_1951))


glasgow_wards_1951$area_km <- units::set_units(glasgow_wards_1951$area, km^2)

Make division shape files, and calculate area (stopped working, need to fix!)


# glasgow_divisions_1951 <- glasgow_wards_1951 %>%
#   group_by(division) %>% 
#   summarize(geometry = st_union(geometry)) %>%
#   nngeo::st_remove_holes() %>%
#   mutate(area = st_area(glasgow_divisions_1951))
# 
# glasgow_divisions_1951$area_km <- units::set_units(glasgow_divisions_1951$area, km^2)

3. Denominators

Load in the datasets for denonomiators, and check for consistency.


overall_pops <- read_xlsx(path = "2023-11-28_glasgow-acf.xlsx", sheet = "overall_population")

overall_pops %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  datatable()

#shift year to midpoint
overall_pops <- overall_pops %>%
  mutate(year2 = year+0.5)

Note, we have three population estimates:

  1. Population without institutionalised people or people in shipping
  2. Population in institutions
  3. Population in shipping

(Population in shipping is estimated from the 1951 census, so is the same for most years)

3.1 Overall population

First, plot the total population


overall_pops %>%
  ggplot() +
  geom_area(aes(y=total_population, x=year2), alpha=0.5, colour = "mediumseagreen", fill="mediumseagreen") +
  geom_point(aes(y=total_population, x=year2), colour = "mediumseagreen") +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels) +
  labs(
    title = "Glasgow Corporation: total population",
    subtitle = "1950 to 1963",
    x = "Year",
    y = "Population",
    caption = "Mid-year estimates\nMass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)"
  ) +
  theme_ggdist()

NA
NA

Now the population excluding institutionalised and shipping population


overall_pops %>%
  ggplot() +
  geom_area(aes(y=population_without_inst_ship, x=year2), alpha=0.5, colour = "purple", fill="purple") +
  geom_point(aes(y=population_without_inst_ship, x=year2), colour = "purple") +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels) +
  labs(
    title = "Glasgow Corporation: population excluding institutionalised and shipping",
    subtitle = "1950 to 1963",
    x = "Year",
    y = "Population",
    caption = "Mid-year estimates\nMass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)"
  ) +
  theme_ggdist()

NA
NA

3.2 Population by Ward

There are 5 Divisions containing 37 Wards in the Glasgow Corporation, with consistent boundaries over time.

#look-up table for divisions and wards
ward_lookup <- read_xlsx(path = "2023-11-28_glasgow-acf.xlsx", sheet = "divisions_wards")


ward_pops <- read_xlsx(path = "2023-11-28_glasgow-acf.xlsx", sheet = "ward_population")

ward_pops %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  datatable()

#shift year to midpoint
ward_pops <- ward_pops %>%
  mutate(year2 = year+0.5)

#Get the Division population
division_pops <- ward_pops %>%
  group_by(division, year) %>%
  summarise(population_without_inst_ship = sum(population_without_inst_ship, na.rm = TRUE),
            institutions = sum(institutions, na.rm = TRUE),
            shipping = sum(shipping, na.rm = TRUE),
            total_population = sum(total_population, na.rm = TRUE))
`summarise()` has grouped output by 'division'. You can override using the `.groups` argument.
division_pops %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  datatable()
NA

Plot the overall population by Division and Ward


division_pops %>%
  mutate(year2 = year+0.5) %>%
  ggplot() +
  geom_area(aes(y=total_population, x=year2, colour=division, fill=division), alpha=0.8) +
  geom_point(aes(y=total_population, x=year2, colour=division)) +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  facet_wrap(division~.) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels,
                     guide = guide_axis(angle = 90)) +
  scale_fill_brewer(palette = "Set3", name = "") +
  scale_colour_brewer(palette = "Set3", name = "") +
  labs(
    title = "Glasgow Corporation: total population by Division",
    subtitle = "1950 to 1963",
    x = "Year",
    y = "Population",
    caption = "Mid-year estimates\nMass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)"
  ) +
  theme_ggdist() +
  theme(legend.position = "bottom")

NA
NA

ward_pops %>%
  ggplot() +
  geom_area(aes(y=total_population, x=year2, colour=division, fill=division), alpha=0.8) +
  geom_point(aes(y=total_population, x=year2, colour=division)) +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  facet_wrap(ward~., ncol=6) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels,
                     guide = guide_axis(angle = 90)) +
  scale_fill_brewer(palette = "Set3", name="Division") +
  scale_colour_brewer(palette = "Set3", name = "Division") +
  labs(
    title = "Glasgow City: total population by Ward",
    subtitle = "1950 to 1963",
    x = "Year",
    y = "Population",
    caption = "Mid-year estimates\nMass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)"
  ) +
  theme_ggdist() +
  theme(legend.position = "bottom")

ggsave(here("figures/s2.png"), height=10, width=12)

Approximately, how many person-years of follow-up do we have?


overall_pops %>%
  ungroup() %>%
  summarise(across(year, length, .names = "years"),
            across(c(population_without_inst_ship, total_population), sum)) %>%
  mutate(across(where(is.double), comma)) %>%
  datatable()
NA
NA

Change in population by ward


ward_pops %>%
  group_by(ward) %>%
  summarise(pct_change_pop = (last(population_without_inst_ship) - first(population_without_inst_ship))/first(population_without_inst_ship)) %>%
  mutate(pct_change_pop = percent(pct_change_pop)) %>%
  arrange(pct_change_pop) %>%
  datatable()
NA
NA
NA

Output population density by ward and divison for regression modelling

Wards first

(stopped working, need to fix)


# ward_covariates <-  glasgow_wards_1951 %>%
#   left_join(ward_pops) %>%
#   mutate(people_per_km_sq = as.double(population_without_inst_ship/area_km))
# 
# #plot it out
# 
# ward_covariates %>%
#   ggplot() +
#   geom_sf(aes(fill=people_per_km_sq)) + 
#   facet_wrap(year~., ncol=7) +
#   scale_fill_viridis_c(option="A") +
#   theme(legend.position = "bottom",
#         axis.text.x = element_text(angle = 45, hjust=1))
# 
# ggsave(here("figures/ward_pop_density.png"), width=10)
# 
# write_rds(ward_covariates, here("populations/ward_covariates.rds"))

Now divisions first

(stopped working, need to fix)


# division_covariates <-  glasgow_divisions_1951 %>%
#   left_join(division_pops) %>%
#   mutate(people_per_km_sq = as.double(total_population/area_km))
# 
# #plot it out
# 
# division_covariates %>%
#   ggplot() +
#   geom_sf(aes(fill=people_per_km_sq)) + 
#   geom_sf_label(aes(label = division), size=3, fill=NA, label.size = NA, colour="black", family = "Segoe UI") +
#   facet_wrap(year~., ncol=7) +
#   scale_fill_viridis_c(option="G") +
#   theme(legend.position = "bottom",
#         axis.text.x = element_text(angle = 45, hjust=1))
# 
# ggsave(here("figures/division_pop_density.png"), width=10)
# 
# write_rds(division_covariates, here("populations/division_covariates.rds"))

3.3 Population by age and sex


age_sex <- read_xlsx(path = "2023-11-28_glasgow-acf.xlsx", sheet = "age_sex_population") %>%
  pivot_longer(cols = c(male, female),
               names_to = "sex")

#collapse down to smaller age groups to be manageable
age_sex <- age_sex %>%
  ungroup() %>%
  mutate(age = case_when(age == "0 to 4" ~ "00 to 04",
                         age == "5 to 9" ~ "05 to 14",
                         age == "10 to 14" ~ "05 to 14",
                         age == "15 to 19" ~ "15 to 24",
                         age == "20 to 24" ~ "15 to 24",
                         age == "25 to 29" ~ "25 to 34",
                         age == "30 to 34" ~ "25 to 34",
                         age == "35 to 39" ~ "35 to 44",
                         age == "40 to 44" ~ "35 to 44",
                         age == "45 to 49" ~ "45 to 59",
                         age == "50 to 54" ~ "45 to 59",
                         age == "55 to 59" ~ "45 to 59",
                         TRUE ~ "60 & up")) %>%
  group_by(year, age, sex) %>%
  mutate(value = sum(value)) %>%
  ungroup()



m_age_sex <- lm(value ~ splines::ns(year, knots = 3)*age*sex, data = age_sex)

summary(m_age_sex)
Warning: essentially perfect fit: summary may be unreliable

Call:
lm(formula = value ~ splines::ns(year, knots = 3) * age * sex, 
    data = age_sex)

Residuals:
       Min         1Q     Median         3Q        Max 
-1.185e-10  0.000e+00  0.000e+00  0.000e+00  1.185e-10 

Coefficients: (14 not defined because of singularities)
                                                    Estimate Std. Error    t value Pr(>|t|)    
(Intercept)                                        5.222e+04  2.040e-10  2.559e+14   <2e-16 ***
splines::ns(year, knots = 3)1                     -8.043e+03  4.071e-10 -1.976e+13   <2e-16 ***
splines::ns(year, knots = 3)2                             NA         NA         NA       NA    
age05 to 14                                        3.669e+04  2.499e-10  1.468e+14   <2e-16 ***
age15 to 24                                       -3.893e+03  2.499e-10 -1.558e+13   <2e-16 ***
age25 to 34                                       -3.996e+04  2.499e-10 -1.599e+14   <2e-16 ***
age35 to 44                                       -4.230e+04  2.499e-10 -1.693e+14   <2e-16 ***
age45 to 59                                        5.459e+04  2.356e-10  2.317e+14   <2e-16 ***
age60 & up                                         7.533e+04  2.204e-10  3.418e+14   <2e-16 ***
sexmale                                            3.374e+03  2.886e-10  1.169e+13   <2e-16 ***
splines::ns(year, knots = 3)1:age05 to 14         -1.863e+03  4.985e-10 -3.737e+12   <2e-16 ***
splines::ns(year, knots = 3)2:age05 to 14                 NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age15 to 24          7.533e+04  4.985e-10  1.511e+14   <2e-16 ***
splines::ns(year, knots = 3)2:age15 to 24                 NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age25 to 34          1.325e+05  4.985e-10  2.658e+14   <2e-16 ***
splines::ns(year, knots = 3)2:age25 to 34                 NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age35 to 44          1.380e+05  4.985e-10  2.769e+14   <2e-16 ***
splines::ns(year, knots = 3)2:age35 to 44                 NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age45 to 59          3.474e+03  4.700e-10  7.390e+12   <2e-16 ***
splines::ns(year, knots = 3)2:age45 to 59                 NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age60 & up          -8.453e+04  4.397e-10 -1.923e+14   <2e-16 ***
splines::ns(year, knots = 3)2:age60 & up                  NA         NA         NA       NA    
splines::ns(year, knots = 3)1:sexmale             -1.994e+03  5.757e-10 -3.464e+12   <2e-16 ***
splines::ns(year, knots = 3)2:sexmale                     NA         NA         NA       NA    
age05 to 14:sexmale                                1.053e+04  3.534e-10  2.980e+13   <2e-16 ***
age15 to 24:sexmale                                2.352e+04  3.534e-10  6.656e+13   <2e-16 ***
age25 to 34:sexmale                                1.355e+04  3.534e-10  3.833e+13   <2e-16 ***
age35 to 44:sexmale                               -1.727e+03  3.534e-10 -4.888e+12   <2e-16 ***
age45 to 59:sexmale                                2.774e+03  3.332e-10  8.324e+12   <2e-16 ***
age60 & up:sexmale                                -7.761e+04  3.117e-10 -2.490e+14   <2e-16 ***
splines::ns(year, knots = 3)1:age05 to 14:sexmale -2.049e+04  7.051e-10 -2.906e+13   <2e-16 ***
splines::ns(year, knots = 3)2:age05 to 14:sexmale         NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age15 to 24:sexmale -6.780e+04  7.051e-10 -9.616e+13   <2e-16 ***
splines::ns(year, knots = 3)2:age15 to 24:sexmale         NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age25 to 34:sexmale -3.804e+04  7.051e-10 -5.396e+13   <2e-16 ***
splines::ns(year, knots = 3)2:age25 to 34:sexmale         NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age35 to 44:sexmale -1.171e+04  7.051e-10 -1.661e+13   <2e-16 ***
splines::ns(year, knots = 3)2:age35 to 44:sexmale         NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age45 to 59:sexmale -3.473e+04  6.647e-10 -5.224e+13   <2e-16 ***
splines::ns(year, knots = 3)2:age45 to 59:sexmale         NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age60 & up:sexmale   1.056e+05  6.218e-10  1.698e+14   <2e-16 ***
splines::ns(year, knots = 3)2:age60 & up:sexmale          NA         NA         NA       NA    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 3.074e-11 on 44 degrees of freedom
Multiple R-squared:      1, Adjusted R-squared:      1 
F-statistic: 6.006e+29 on 27 and 44 DF,  p-value: < 2.2e-16
age_levels <- age_sex %>% select(age) %>% distinct() %>% pull() 

age_sex_nd <- 
  crossing(
    age=age_levels,
    sex=c("male", "female"),
    year = 1950:1963
  )

pred_pops <- age_sex_nd %>% modelr::add_predictions(m_age_sex)
Warning: prediction from a rank-deficient fit may be misleading
pred_pops %>%
  ggplot(aes(x=year, y=pred, colour=age)) +
  geom_line() +
  geom_point() +
  facet_grid(sex~.) +
  scale_y_continuous(labels = comma, limits = c(0, 125000))


#How well do they match up with our overall populations?
pred_pops %>%
  group_by(year) %>%
  summarise(sum_pred_pop = sum(pred)) %>%
  right_join(overall_pops) %>%
  select(year, sum_pred_pop, population_without_inst_ship, total_population) %>%
  pivot_longer(cols = c(sum_pred_pop, population_without_inst_ship, total_population)) %>%
  ggplot(aes(x=year, y=value, colour=name)) +
  geom_point() +
  scale_y_continuous(labels = comma, limits = c(800000, 1250000))
Joining with `by = join_by(year)`

pred_pops %>%
  group_by(year, sex) %>%
  summarise(sum = sum(pred)) %>%
  group_by(year) %>%
  mutate(sex_ratio = first(sum)/last(sum))
`summarise()` has grouped output by 'year'. You can override using the `.groups` argument.

What percentage of adults (15+ participated in the intervention in 1957)?


pred_pops %>%
  ungroup() %>%
  filter(year==1957) %>%
  filter(age != "00 to 04",
         age != "05 to 14") %>%
  summarise(total_pop = sum(pred)) %>%
  mutate(cxr_screened = 622349) %>%
  mutate(pct_pop_cxr_screened = percent(cxr_screened/total_pop))

pred_pops %>%
  ungroup() %>%
  filter(year==1957) %>%
  filter(age != "00 to 04",
         age != "05 to 14") %>%
  summarise(total_pop = sum(pred), .by=sex) %>%
  mutate(cxr_screened = c(340474, 281875)) %>%
  mutate(pct_pop_cxr_screened = percent(cxr_screened/total_pop))
NA
NA

Population pyramids


label_abs <- function(x) {
  comma(abs(x))
}


pred_pops %>%
  ungroup() %>%
  group_by(year) %>%
  mutate(year_pop = sum(pred),
         age_sex_pct = percent(pred/year_pop, accuracy=0.1)) %>%
  mutate(sex = case_when(sex=="male" ~ "Male",
                         sex=="female" ~ "Female")) %>%
  ggplot(
    aes(x = age, fill = sex, 
        y = ifelse(test = sex == "Female",yes = -pred, no = pred))) + 
  geom_bar(stat = "identity") +
  geom_text(aes(label = age_sex_pct),
            position= position_stack(vjust=0.5), colour="white", size=2.5) +
  facet_wrap(year~., ncol=7) +
  coord_flip() +
  scale_y_continuous(labels = label_abs) +
  scale_fill_manual(values = c("mediumseagreen", "purple"), name="") +
  theme_ggdist() +
  theme(axis.text.x = element_text(angle=90, hjust = 1, vjust=0.5),
        legend.position = "bottom",
        panel.border = element_rect(colour = "grey78", fill=NA)) +
  labs(x="", y="") 


ggsave(here("figures/s3.png"), width=10)
Saving 10 x 4.5 in image

Not perfect, but resonably good. But ahhhhh… the age groups don’t align with the case notification age groups! Come back to think about this later.

4. Tuberculosis cases

Import the tuberculosis cases dataset

4.1 Overall notifications

Overall, by year.


cases_by_year <- read_xlsx("2023-11-28_glasgow-acf.xlsx", sheet = "by_year")

cases_by_year%>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  datatable()


#shift year to midpoint
cases_by_year <- cases_by_year %>%
  mutate(year2 = year+0.5)

Plot the overall number of case notified per year, by pulmonary and extra pulmonary classification.


cases_by_year %>%
  select(-total_notifications, -year) %>%
  pivot_longer(cols = c(pulmonary_notifications, `non-pulmonary_notifications`)) %>%
  mutate(name = case_when(name == "pulmonary_notifications" ~ "Pulmonary TB",
                          name == "non-pulmonary_notifications" ~ "Extra-pulmonary TB")) %>%
  ggplot() +
  geom_area(aes(y=value, x=year2, group = name, fill=name), alpha=0.5) +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels) +
  scale_fill_brewer(palette = "Set1", name="") +
  labs(
    title = "Glasgow Corporation: Tuberculosis notifications",
    subtitle = "1950 to 1963, by TB disease classification",
    x = "Year",
    y = "Number of cases",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)"
  ) +
  theme_ggdist() +
  theme(legend.position = "bottom")

NA
NA

4.2 Notifications by Division

Read in the datasets and merge together.


#list all the sheets
all_sheets <- excel_sheets("2023-11-28_glasgow-acf.xlsx")

#get the ward sheets
ward_sheets <- enframe(all_sheets) %>%
  filter(grepl("by_ward", value)) %>%
  pull(value)


cases_by_ward_sex_year <- map_df(ward_sheets, ~read_xlsx(path = "2023-11-28_glasgow-acf.xlsx",
                                sheet = .))

cases_by_ward_sex_year %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  datatable()
NA

Aggregate together to get cases by division


cases_by_division <- cases_by_ward_sex_year %>%
  left_join(ward_lookup) %>%
  group_by(division, year, tb_type) %>%
  summarise(cases = sum(cases, na.rm = TRUE))
Joining with `by = join_by(ward)``summarise()` has grouped output by 'division', 'year'. You can override using the `.groups` argument.
#shift year to midpoint
cases_by_division <- cases_by_division %>%
  mutate(year2 = year+0.5) %>%
  ungroup()

cases_by_division  %>%
  select(-year2) %>%
  select(year, everything()) %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  datatable()


cases_by_division %>%
  mutate(tb_type = case_when(tb_type == "Pulmonary" ~ "Pulmonary TB",
                          tb_type == "Non-Pulmonary" ~ "Extra-pulmonary TB")) %>%
  ggplot() +
  geom_area(aes(y=cases, x=year2, group = tb_type, fill=tb_type), alpha=0.5) +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels,
                     guide = guide_axis(angle = 90)) +
  facet_wrap(division~., scales = "free_y") +
  scale_fill_brewer(palette = "Set1", name="") +
  labs(
    title = "Glasgow Corporation: Tuberculosis notifications by Division",
    subtitle = "1950 to 1963, by TB disease classification",
    x = "Year",
    y = "Number of cases",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)\nNote: extra-pulmonary TB cases by Division/Ward not reported in 1962-1963"
  ) +
  theme_ggdist() +
  theme(legend.position = "bottom")

4.3 Notifications by ward



cases_by_ward <- cases_by_ward_sex_year %>%
  group_by(ward, year, tb_type) %>%
  summarise(cases = sum(cases, na.rm = TRUE)) %>%
  ungroup()
`summarise()` has grouped output by 'ward', 'year'. You can override using the `.groups` argument.
cases_by_ward %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  select(year, everything()) %>%
  datatable()

#shift year to midpoint
cases_by_ward <- cases_by_ward %>%
  mutate(year2 = year+0.5)

cases_by_ward %>%
  mutate(tb_type = case_when(tb_type == "Pulmonary" ~ "Pulmonary TB",
                          tb_type == "Non-Pulmonary" ~ "Extra-pulmonary TB")) %>%
  ggplot() +
  geom_area(aes(y=cases, x=year2, group = tb_type, fill=tb_type), alpha=0.8) +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels,
                     guide = guide_axis(angle = 90)) +
  facet_wrap(ward~., scales = "free_y") +
  scale_fill_brewer(palette = "Set1", name="") +
  labs(
    title = "Glasgow Corporation: Tuberculosis notifications by Ward",
    subtitle = "1950 to 1963, by TB disease classification",
    x = "Year",
    y = "Number of cases",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)\nNote: extra-pulmonary TB cases by Division/Ward not reported in 1962-1963"
  ) +
  theme(legend.position = "bottom")

NA
NA

4.4 Notifications by age and sex

As we don’t have denominators, we will just model the change in counts.


#list all the sheets
all_sheets <- excel_sheets("2023-11-28_glasgow-acf.xlsx")

#get the ward sheets
age_sex_sheets <- enframe(all_sheets) %>%
  filter(grepl("by_age_sex", value)) %>%
  pull(value)


cases_by_age_sex <- map_df(age_sex_sheets, ~read_xlsx(path = "2023-11-28_glasgow-acf.xlsx",
                                sheet = .))

cases_by_age_sex %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  datatable()
NA
NA

5 TB case notification rates

5.1 Overall TB case notification rates

Now calculate case notification rates per 100,000 population

Merge the notification and population denominator datasets together.

Here we need to include the whole population (with shipping and institutions) as they are included in the notifications.


overall_inc <- overall_pops %>%
  left_join(cases_by_year)
Joining with `by = join_by(year, year2)`
overall_inc <- overall_inc %>%
  mutate(inc_pulm_100k = pulmonary_notifications/total_population*100000,
         inc_ep_100k = `non-pulmonary_notifications`/total_population*100000,
         inc_100k = total_notifications/total_population*100000)

overall_inc %>%
  select(year, inc_100k, inc_pulm_100k, inc_ep_100k) %>%
  mutate_at(.vars = vars(inc_100k, inc_pulm_100k, inc_ep_100k),
            .funs = funs(round)) %>%
  datatable()
Warning: `funs()` was deprecated in dplyr 0.8.0.
Please use a list of either functions or lambdas: 

  # Simple named list: 
  list(mean = mean, median = median)

  # Auto named with `tibble::lst()`: 
  tibble::lst(mean, median)

  # Using lambdas
  list(~ mean(., trim = .2), ~ median(., na.rm = TRUE))

overall_inc %>%
  select(year2, inc_pulm_100k, inc_ep_100k) %>%
  pivot_longer(cols = c(inc_pulm_100k, `inc_ep_100k`)) %>%
  mutate(name = case_when(name == "inc_pulm_100k" ~ "Pulmonary TB",
                          name == "inc_ep_100k" ~ "Extra-pulmonary TB")) %>%
  ggplot() +
  geom_area(aes(y=value, x=year2, group = name, fill=name), alpha=0.5) +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels) +
  scale_fill_brewer(palette = "Set1", name="") +
  labs(
    title = "Glasgow Corporation: Tuberculosis case notification rate",
    subtitle = "1950 to 1963, by TB disease classification",
    x = "Year",
    y = "Case notification rate (per 100,000)",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)"
  ) +
  theme_ggdist() +
  theme(legend.position = "bottom")

NA
NA
NA

5.2 TB case notification rates by Division


division_inc <- division_pops %>%
  left_join(cases_by_division)
Joining with `by = join_by(division, year)`
division_inc <- division_inc %>%
  mutate(inc_100k = cases/total_population*100000)

division_inc %>%
  select(year, division, tb_type, inc_100k) %>%
  mutate_at(.vars = vars(inc_100k),
            .funs = funs(round)) %>%
  datatable()
Warning: `funs()` was deprecated in dplyr 0.8.0.
Please use a list of either functions or lambdas: 

  # Simple named list: 
  list(mean = mean, median = median)

  # Auto named with `tibble::lst()`: 
  tibble::lst(mean, median)

  # Using lambdas
  list(~ mean(., trim = .2), ~ median(., na.rm = TRUE))

division_inc %>%
  mutate(tb_type = case_when(tb_type == "Pulmonary" ~ "Pulmonary TB",
                          tb_type == "Non-Pulmonary" ~ "Extra-pulmonary TB")) %>%
  ggplot() +
  geom_area(aes(y=inc_100k, x=year2, group = tb_type, fill=tb_type), alpha=0.5) +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels,
                     guide = guide_axis(angle = 90)) +
  facet_wrap(division~.) +
  scale_fill_brewer(palette = "Set1", name="") +
  labs(
    title = "Glasgow Corporation: Tuberculosis case notification rate, by Division",
    subtitle = "1950 to 1963, by TB disease classification",
    x = "Year",
    y = "Case notification rate (per 100,000)",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)\nNote: extra-pulmonary TB cases by Division/Ward not reported in 1962-1963"
  ) +
  theme_ggdist() +
  theme(legend.position = "bottom")

NA
NA
NA

5.2 TB case notification rates by Ward

Here we will filter out the institutions and harbour from the denominators, as we don’t have reliable population denominators for them.


ward_inc <- ward_pops %>%
  left_join(cases_by_ward)
Joining with `by = join_by(ward, year, year2)`
ward_inc <- ward_inc %>%
  mutate(inc_100k = cases/population_without_inst_ship*100000)

ward_inc %>%
  select(year, ward, tb_type, inc_100k) %>%
  mutate_at(.vars = vars(inc_100k),
            .funs = funs(round)) %>%
  datatable()
Warning: `funs()` was deprecated in dplyr 0.8.0.
Please use a list of either functions or lambdas: 

  # Simple named list: 
  list(mean = mean, median = median)

  # Auto named with `tibble::lst()`: 
  tibble::lst(mean, median)

  # Using lambdas
  list(~ mean(., trim = .2), ~ median(., na.rm = TRUE))

ward_inc %>%
  mutate(tb_type = case_when(tb_type == "Pulmonary" ~ "Pulmonary TB",
                          tb_type == "Non-Pulmonary" ~ "Extra-pulmonary TB")) %>%
  ggplot() +
  geom_area(aes(y=inc_100k, x=year2, group = tb_type, fill=tb_type), alpha=0.5) +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels,
                     guide = guide_axis(angle = 90)) +
  facet_wrap(ward~.) +
  scale_fill_brewer(palette = "Set1", name="") +
  labs(
    title = "Glasgow Corporation: Tuberculosis case notification rate, by Ward",
    subtitle = "1950 to 1963, by TB disease classification",
    x = "Year",
    y = "Incidence (per 100,000)",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)\nNote: extra-pulmonary TB cases by Division/Ward not reported in 1962-1963"
  ) +
  theme(legend.position = "bottom")

NA
NA
NA
NA

On a map


st_as_sf(left_join(ward_inc, glasgow_wards_1951)) %>%
  filter(tb_type=="Pulmonary") %>%
  ggplot() +
  geom_sf(aes(fill=inc_100k)) +
  facet_wrap(year~., ncol = 7) +
  scale_fill_viridis_c(name="Case notification rate (per 100,000)",
                       option = "A") +
  theme_ggdist() +
  theme(legend.position = "top",
        legend.key.width = unit(2, "cm"),
        panel.border = element_rect(colour = "grey78", fill=NA)) +
  guides(fill=guide_colorbar(title.position = "top"))
Joining with `by = join_by(division, ward, ward_number)`

6. TB Mortality

6.1 Overall Mortality

Import the TB mortality data.

First, overall deaths. Note that in the original reports, we have a pulmonary TB death rate per million for all years, and numbers of pulmonary TB deaths for each year apart from 1950.


#get the overall mortality sheets
deaths_sheets <- enframe(all_sheets) %>%
  filter(grepl("deaths", value)) %>%
  pull(value)


overall_deaths <- map_df(deaths_sheets, ~read_xlsx(path = "2023-11-28_glasgow-acf.xlsx",
                                sheet = .))

overall_deaths %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  datatable()
NA
NA
NA

Plot the raw numbers of pulmonary deaths


overall_deaths %>%
  ggplot(aes(x=year, y=pulmonary_deaths)) +
  geom_line(colour = "#DE0D92") +
  geom_point(colour = "#DE0D92") +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  labs(y="Pulmonary TB deaths per year",
       x = "Year",
       title = "Numbers of pulmonary TB deaths",
       subtitle = "Glasgow, 1950-1963",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)\nNote: no data for 1950") +
  theme_ggdist() +
  theme(panel.border = element_rect(colour = "grey78", fill=NA))

NA
NA

Now the incidence of pulmonary TB death

overall_deaths %>%
  ggplot(aes(x=year, y=pulmonary_death_rate_per_100k)) +
  geom_line(colour = "#4D6CFA") +
  geom_point(colour = "#4D6CFA") +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels) +
  labs(y="Annual incidence of death (per 100,000)",
       x = "Year",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)") +
  theme_ggdist() +
  theme(panel.border = element_rect(colour = "grey78", fill=NA))

ggsave(here("figures/s7.png"), width=10)
Saving 10 x 4.5 in image

6. Table 1

Make Table 1 here, and save for publication.


overall_pops %>% 
  select(year, total_population) %>%
  left_join(overall_inc %>%
              select(year, 
                     pulmonary_notifications, inc_pulm_100k,
                     `non-pulmonary_notifications`, inc_ep_100k,
                     total_notifications, inc_100k)) %>%
  left_join(overall_deaths %>%
              select(year,
                     pulmonary_deaths, pulmonary_death_rate_per_100k)) %>%
  mutate(across(where(is.numeric) & !(year),  ~round(., digits=1))) %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) 
Joining with `by = join_by(year)`Joining with `by = join_by(year)`

Prepare the datasets for modelling


mdata <- ward_inc %>%
  filter(tb_type=="Pulmonary") %>%
  mutate(acf_period = case_when(year %in% c(1950:1956) ~ "a. pre-acf",
                                year %in% c(1957) ~ "b. acf",
                                year %in% c(1958:1963) ~ "c. post-acf")) %>%
  group_by(ward) %>%
  mutate(y_num = row_number()) %>%
  ungroup()


mdata_extrapulmonary <- ward_inc %>%
  filter(tb_type=="Non-Pulmonary") %>%
  mutate(acf_period = case_when(year %in% c(1950:1956) ~ "a. pre-acf",
                                year %in% c(1957) ~ "b. acf",
                                year %in% c(1958:1963) ~ "c. post-acf")) %>%
  group_by(ward) %>%
  mutate(y_num = row_number()) %>%
  ungroup() %>% 
  filter(year<=1961) #no data for 1962 and 1963


#scaffold for overall predictions
overall_scaffold <- mdata %>%
    select(year, year2, y_num, acf_period, population_without_inst_ship, ward, cases) %>%
    group_by(year, year2, y_num, acf_period) %>%
    summarise(population_without_inst_ship = sum(population_without_inst_ship),
              cases = sum(cases)) %>%
    ungroup() %>%
    mutate(inc_100k = cases/population_without_inst_ship*100000) %>%
    left_join(mdata_extrapulmonary %>% group_by(year) %>%
                summarise(cases_extrapulmonary = sum(cases))) %>%
    mutate(inc_100k_extrapulmonary = cases_extrapulmonary/population_without_inst_ship*100000)
`summarise()` has grouped output by 'year', 'year2', 'y_num'. You can override using the `.groups` argument.Joining with `by = join_by(year)`

7. Pulmonary TB model

7.1 Fit the model and priors

This models the case notification rate over time, with a step change for the intervention, and slope change after the intervention.

Work on the priors a bit. We will build up from less complex to more complex.

  1. intercept only, to predict count of cases

at the intercept, we expect somewhere around 2500. We will set the standard deviation to both 0.5 and 1 to check what it looks like

# 
# c(prior(lognormal(7.600902, 0.5)), #log(2500) = 7.600902
#   prior(lognormal(7.600902, 1))) %>% 
#   parse_dist() %>% 
#   
#   ggplot(aes(y = prior, dist = .dist, args = .args)) +
#   stat_halfeye(.width = c(.5, .95)) +
#   scale_y_discrete(NULL, labels = str_c("lognormal(log(2000), ", c(0.5, 1), ")"),
#                    expand = expansion(add = 0.1)) +
#   xlab(expression(exp(italic(p)(beta[0])))) +
#   coord_cartesian(xlim = c(0,15000))
# 
# 
# prior(gamma(1, 0.01)) %>%
#   parse_dist() %>%
#   ggplot(aes(y=prior, dist = .dist, args = .args)) +
#   stat_halfeye(.width = c(0.5, 0.95))
# 
# #now fit to a model, and plot some prior realisations
# 
# m_prior1 <- brm(
#   cases ~ 0 + Intercept,
#   family = negbinomial(),
#   data = overall_scaffold,
#   sample_prior = "only",
#   prior = prior(normal(log(2000), 0.5), class = b, coef = Intercept) +
#           prior(gamma(1, 0.01), class = shape)
# )
# 
# add_epred_draws(object=m_prior1,
#                 newdata = tibble(intercept=1)) %>%
#   ggplot(aes(x=intercept, y=.epred)) +
#   stat_halfeye() +
#   scale_y_log10(labels = comma)

Now try to add in a term for the effect of y_num. We anticpate that the number of cases will decline by about 1-5% per year. However, as we are pretty uncertain about this, we will just encode a weakly regularising prior to restrict the year size to sensible ranges.

# 
# 
# m_prior2 <- brm(
#   cases ~ 0 + Intercept + y_num,
#   family = negbinomial(),
#   data = overall_scaffold,
#   sample_prior = "only",
#   prior = prior(normal(log(2000), 0.5), class = b, coef = Intercept) +
#           prior(gamma(1, 0.01), class = shape) +
#           prior(normal(0, 0.01), class = b, coef = y_num)
# )
# 
# add_epred_draws(object=m_prior2,
#                 newdata = overall_scaffold) %>%
#   ggplot(aes(x=year, y=.epred)) +
#   stat_halfeye() +
#   scale_y_log10(label=comma)

Now we want to add in a prior for the effect of the acf_intervention. We anticipate the peak to be anywhere between no effect, and a tripling

# 
# m_prior3 <- brm(
#   cases ~ 0 + Intercept + y_num + acf_period,
#   family = negbinomial(),
#   data = overall_scaffold,
#   sample_prior = "only",
#   prior = prior(normal(log(2000), 0.5), class = b, coef = Intercept) +
#           prior(gamma(1, 0.01), class = shape) +
#           prior(normal(0, 0.01), class = b, coef = y_num) +
#           prior(normal(0, 0.001), class = b)
# )
# 
# 
# add_epred_draws(object=m_prior3,
#                 newdata = overall_scaffold) %>%
#   ggplot(aes(x=year, y=.epred)) +
#   stat_halfeye() +
#   scale_y_log10(labels = comma)
# 

Now we look and see what it looks like with the interactions

# 
# m_prior4 <- brm(
#   cases ~ 0 + Intercept + y_num + acf_period + y_num:acf_period,
#   family = negbinomial(),
#   data = overall_scaffold,
#   sample_prior = "only",
#   prior = prior(normal(log(2500), 1), class = b, coef = Intercept) +
#           prior(gamma(1, 0.01), class = shape) +
#           prior(normal(0, 0.01), class = b)
# )
# 
# add_epred_draws(object=m_prior4,
#                 newdata = overall_scaffold) %>%
#   ggplot(aes(x=year, y=.epred)) +
#   stat_halfeye() +
#   scale_y_log10(label=comma)
# 
# 

Now try adding in the random intercepts


# c(prior(lognormal(3.912023, 0.5)), #log(50) = 3.912023
#   prior(lognormal(3.912023, 1))) %>% 
#   parse_dist() %>% 
#   
#   ggplot(aes(y = prior, dist = .dist, args = .args)) +
#   stat_halfeye(.width = c(.5, .95)) +
#   scale_y_discrete(NULL, labels = str_c("lognormal(log(50), ", c(0.5, 1), ")"),
#                    expand = expansion(add = 0.1)) +
#   xlab(expression(exp(italic(p)(beta[0])))) +
#   coord_cartesian(xlim = c(0,400))
# 
# 
# m_prior5 <- brm(
#   cases ~ y_num + acf_period + y_num:acf_period + ( 1 | ward),
#   family = negbinomial(),
#   data = mdata,
#   sample_prior = "only",
#   prior = prior(normal(log(50), 1), class = Intercept) +
#           prior(gamma(1, 0.01), class = shape) +
#           prior(normal(0, 0.01), class = b) +
#           prior(exponential(1), class=sd)
# )
# 
# 
# add_epred_draws(object=m_prior5,
#                 newdata = mdata,
#                 re_formula = NA) %>%
#   ggplot(aes(x=year, y=.epred)) +
#   stat_halfeye() +
#   scale_y_log10(label=comma)
# 
# add_epred_draws(object=m_prior5,
#                 newdata = mdata,
#                 re_formula = NA) %>%
#   ggplot(aes(x=year, y=.epred)) +
#   stat_halfeye() +
#   scale_y_log10(label=comma) +
#   facet_wrap(ward~.)

And add in the random slopes

# 
# m_prior6 <- brm(
#   cases ~ 1 + y_num + acf_period + y_num:acf_period + (1 + y_num*acf_period | ward),
#   family = negbinomial(),
#   data = mdata,
#   sample_prior = "only",
#   prior = prior(gamma(1, 0.01), class = shape) +
#           prior(normal(0, 0.1), class = b) +
#           prior(exponential(1), class=sd) +
#           prior(lkj(2), class=cor)
# )
# 
# 
# 
# m_prior6 <- brm(
#   cases ~ 0 + Intercept + y_num + acf_period + y_num:acf_period + ( y_num*acf_period | ward),
#   family = negbinomial(),
#   data = mdata,
#   sample_prior = "only",
#   prior = prior(normal(log(50), 1), class = b, coef = Intercept) +
#           prior(gamma(1, 0.01), class = shape) +
#           prior(normal(0, 0.01), class = b) +
#           prior(exponential(100), class=sd) +
#           prior(lkj(2), class=cor)
# )


# add_epred_draws(object=m_prior6,
#                 newdata = mdata,
#                 re_formula = NA) %>%
#   ggplot(aes(x=year, y=.epred)) +
#   stat_halfeye() +
#   scale_y_log10(label=comma)
# 
# add_epred_draws(object=m_prior6,
#                 newdata = mdata,
#                 re_formula = ~( 1 + y_num + acf_period | ward)) %>%
#   ggplot(aes(x=year, y=.epred)) +
#   stat_halfeye() +
#   scale_y_log10(label=comma) +
#   facet_wrap(ward~.)
# 
# plot_counterfactual(model_data = overall_scaffold, model=m_prior6, outcome = inc_100k, 
#                     population_denominator = population_without_inst_ship, re_formula = NA)
# 
# plot_counterfactual(model_data = mdata, model=m_prior6, outcome = inc_100k, 
#                     population_denominator = population_without_inst_ship, grouping_var = ward, ward,
#                     re_formula = ~( 1 + y_num + acf_period | ward))

Issue here is the non-centred parameterisation of the intercept prior… Feel like this is a more interpretable way to set priors… but will revert to centred parameterisation for the meantime.

# m_centered_prior <- brm(
#   cases ~ 1 + y_num*acf_period + (1 + y_num*acf_period | ward) + offset(log(population_without_inst_ship)),
#                   data = mdata,
#                   family = negbinomial(),
#                   seed = 1234,
#                   chains = 4, cores = 4,
#                   prior = prior(normal(0,1000), class = Intercept) +
#                           prior(gamma(0.01, 0.01), class = shape) +
#                           prior(normal(0, 1), class = b) +
#                           prior(exponential(1), class=sd) +
#                           prior(lkj(2), class=cor),
#                   sample_prior = "only")
# 
# plot(m_centered_prior)
# 
# plot_counterfactual(model_data = overall_scaffold, model=m_centered_prior, outcome = inc_100k, 
#                     population_denominator = population_without_inst_ship, re_formula = NA)
# 
# plot_counterfactual(model_data = mdata, model=m_centered_prior, outcome = inc_100k, 
#                     population_denominator = population_without_inst_ship, grouping_var = ward, ward,
#                     re_formula = ~( 1 + y_num*acf_period | ward))

Look at the mean and variance of counts (counts of pulmonary notifications are what we are predicting)


#Mean of counts per year
mean(mdata$cases)
[1] 49.5551
#variance of counts per year
var(mdata$cases)
[1] 930.1002

Quite a bit of over-dispersion here, so negative binomial distribution might be a better choice of distributional family than Poisson.

Fit the model with the data

m_pulmonary <- brm(
  cases ~ 1 + y_num*acf_period + (1 + y_num*acf_period | ward) + offset(log(population_without_inst_ship)),
                  data = mdata,
                  family = negbinomial(),
                  seed = 1234,
                  chains = 4, cores = 4,
                  prior = prior(normal(0,1), class = Intercept) +
                          prior(gamma(0.01, 0.01), class = shape) +
                          prior(normal(0, 1), class = b) +
                          prior(exponential(1), class=sd) +
                          prior(lkj(4), class=cor),
  control = list(adapt_delta = 0.9))
Compiling Stan program...
Start sampling
starting worker pid=42407 on localhost:11264 at 11:31:54.645
starting worker pid=42421 on localhost:11264 at 11:31:54.830
starting worker pid=42435 on localhost:11264 at 11:31:55.011
starting worker pid=42449 on localhost:11264 at 11:31:55.190

SAMPLING FOR MODEL 'anon_model' NOW (CHAIN 1).
Chain 1: 
Chain 1: Gradient evaluation took 0.000289 seconds
Chain 1: 1000 transitions using 10 leapfrog steps per transition would take 2.89 seconds.
Chain 1: Adjust your expectations accordingly!
Chain 1: 
Chain 1: 
Chain 1: Iteration:    1 / 2000 [  0%]  (Warmup)

SAMPLING FOR MODEL 'anon_model' NOW (CHAIN 2).
Chain 2: 
Chain 2: Gradient evaluation took 0.000359 seconds
Chain 2: 1000 transitions using 10 leapfrog steps per transition would take 3.59 seconds.
Chain 2: Adjust your expectations accordingly!
Chain 2: 
Chain 2: 
Chain 2: Iteration:    1 / 2000 [  0%]  (Warmup)

SAMPLING FOR MODEL 'anon_model' NOW (CHAIN 3).
Chain 3: 
Chain 3: Gradient evaluation took 0.00027 seconds
Chain 3: 1000 transitions using 10 leapfrog steps per transition would take 2.7 seconds.
Chain 3: Adjust your expectations accordingly!
Chain 3: 
Chain 3: 
Chain 3: Iteration:    1 / 2000 [  0%]  (Warmup)

SAMPLING FOR MODEL 'anon_model' NOW (CHAIN 4).
Chain 4: 
Chain 4: Gradient evaluation took 0.00029 seconds
Chain 4: 1000 transitions using 10 leapfrog steps per transition would take 2.9 seconds.
Chain 4: Adjust your expectations accordingly!
Chain 4: 
Chain 4: 
Chain 4: Iteration:    1 / 2000 [  0%]  (Warmup)
Chain 2: Iteration:  200 / 2000 [ 10%]  (Warmup)
Chain 3: Iteration:  200 / 2000 [ 10%]  (Warmup)
Chain 1: Iteration:  200 / 2000 [ 10%]  (Warmup)
Chain 4: Iteration:  200 / 2000 [ 10%]  (Warmup)
Chain 2: Iteration:  400 / 2000 [ 20%]  (Warmup)
Chain 3: Iteration:  400 / 2000 [ 20%]  (Warmup)
Chain 1: Iteration:  400 / 2000 [ 20%]  (Warmup)
Chain 4: Iteration:  400 / 2000 [ 20%]  (Warmup)
Chain 3: Iteration:  600 / 2000 [ 30%]  (Warmup)
Chain 2: Iteration:  600 / 2000 [ 30%]  (Warmup)
Chain 1: Iteration:  600 / 2000 [ 30%]  (Warmup)
Chain 4: Iteration:  600 / 2000 [ 30%]  (Warmup)
Chain 3: Iteration:  800 / 2000 [ 40%]  (Warmup)
Chain 1: Iteration:  800 / 2000 [ 40%]  (Warmup)
Chain 2: Iteration:  800 / 2000 [ 40%]  (Warmup)
Chain 4: Iteration:  800 / 2000 [ 40%]  (Warmup)
Chain 3: Iteration: 1000 / 2000 [ 50%]  (Warmup)
Chain 3: Iteration: 1001 / 2000 [ 50%]  (Sampling)
Chain 1: Iteration: 1000 / 2000 [ 50%]  (Warmup)
Chain 1: Iteration: 1001 / 2000 [ 50%]  (Sampling)
Chain 2: Iteration: 1000 / 2000 [ 50%]  (Warmup)
Chain 2: Iteration: 1001 / 2000 [ 50%]  (Sampling)
Chain 4: Iteration: 1000 / 2000 [ 50%]  (Warmup)
Chain 4: Iteration: 1001 / 2000 [ 50%]  (Sampling)
Chain 3: Iteration: 1200 / 2000 [ 60%]  (Sampling)
Chain 1: Iteration: 1200 / 2000 [ 60%]  (Sampling)
Chain 2: Iteration: 1200 / 2000 [ 60%]  (Sampling)
Chain 4: Iteration: 1200 / 2000 [ 60%]  (Sampling)
Chain 3: Iteration: 1400 / 2000 [ 70%]  (Sampling)
Chain 1: Iteration: 1400 / 2000 [ 70%]  (Sampling)
Chain 2: Iteration: 1400 / 2000 [ 70%]  (Sampling)
Chain 4: Iteration: 1400 / 2000 [ 70%]  (Sampling)
Chain 3: Iteration: 1600 / 2000 [ 80%]  (Sampling)
Chain 1: Iteration: 1600 / 2000 [ 80%]  (Sampling)
Chain 2: Iteration: 1600 / 2000 [ 80%]  (Sampling)
Chain 4: Iteration: 1600 / 2000 [ 80%]  (Sampling)
Chain 3: Iteration: 1800 / 2000 [ 90%]  (Sampling)
Chain 1: Iteration: 1800 / 2000 [ 90%]  (Sampling)
Chain 2: Iteration: 1800 / 2000 [ 90%]  (Sampling)
Chain 4: Iteration: 1800 / 2000 [ 90%]  (Sampling)
Chain 3: Iteration: 2000 / 2000 [100%]  (Sampling)
Chain 3: 
Chain 3:  Elapsed Time: 47.08 seconds (Warm-up)
Chain 3:                37.008 seconds (Sampling)
Chain 3:                84.088 seconds (Total)
Chain 3: 
Chain 1: Iteration: 2000 / 2000 [100%]  (Sampling)
Chain 1: 
Chain 1:  Elapsed Time: 48.099 seconds (Warm-up)
Chain 1:                37.204 seconds (Sampling)
Chain 1:                85.303 seconds (Total)
Chain 1: 
Chain 2: Iteration: 2000 / 2000 [100%]  (Sampling)
Chain 2: 
Chain 2:  Elapsed Time: 49.108 seconds (Warm-up)
Chain 2:                36.908 seconds (Sampling)
Chain 2:                86.016 seconds (Total)
Chain 2: 
Chain 4: Iteration: 2000 / 2000 [100%]  (Sampling)
Chain 4: 
Chain 4:  Elapsed Time: 50.389 seconds (Warm-up)
Chain 4:                36.907 seconds (Sampling)
Chain 4:                87.296 seconds (Total)
Chain 4: 

7.2 Summarise change in CNRs

Summarise the posterior in graphical form


f1b <- plot_counterfactual(model_data = overall_scaffold, model = m_pulmonary, 
                           population_denominator = population_without_inst_ship, outcome = inc_100k, grouping_var=NULL,
                           re_formula = NA)
  
f1b

Make this into a figure combined with the map of empirical data


f1a <- st_as_sf(left_join(ward_inc, glasgow_wards_1951)) %>%
  filter(tb_type=="Pulmonary") %>%
  ggplot() +
  geom_sf(aes(fill=inc_100k)) +
  facet_wrap(year~., ncol = 7) +
  scale_fill_viridis_c(name="Case notification rate (per 100,000)",
                       option = "A") +
  theme_ggdist() +
  theme(panel.border = element_rect(colour = "grey78", fill=NA),
        legend.position = "top",
        legend.key.width = unit(2, "cm"),
        legend.title.align = 0.5,
        text = element_text(size=8),
        axis.text.x = element_text(angle=45, size=6, hjust=1),
        axis.text.y = element_text(size=6)) +
  guides(fill=guide_colorbar(title.position = "top"))

(f1a / f1b) + plot_annotation(tag_levels = "A")

ggsave(here("figures/f1.png"))

Summary of change in notifications numerically


overall_change <- summarise_change(model_data=overall_scaffold, model=m_pulmonary, 
                                   population_denominator=population_without_inst_ship, grouping_var=NULL, re_formula = NA)
`summarise()` has grouped output by '.draw'. You can override using the `.groups` argument.
#want to keep the summary estimates here
tokeep <- c("peak_summary", "level_summary", "slope_summary")

#summary measures in a table
overall_change %>%
  keep((names(.) %in% tokeep)) %>%
  bind_rows() %>%
  mutate(across(c(estimate:.upper), number, accuracy=0.01)) %>%
  select(measure, everything()) %>%
  datatable()
NA
NA

7.3 Compared to counterfactual

Numbers of pulmonary TB cases averted compared to counterfactual per year.

Total pulmonary TB cases averted between 1958 and 1963

7.4 Correlation between RR.peak, RR.level, and RR.slope

What are the correlations between peak, level, and slope?


#RR.peak histogram
a <- overall_change$peak_draws %>%
  ggplot() +
  geom_histogram(aes(x=estimate), fill="darkblue", colour="darkblue", alpha=0.3)+
  scale_fill_gradient(high="lightblue1",low="darkblue") +
  theme_ggdist() +
  theme(legend.position = "none",
        panel.border = element_rect(colour = "grey78", fill=NA)) +
  labs(x="RR.peak",
       y="")

#RR. level histogram
b <- overall_change$level_draws  %>%
  ggplot() +
  geom_histogram(aes(x=estimate), fill="darkblue", colour="darkblue", alpha=0.3)+
  scale_fill_gradient(high="lightblue1",low="darkblue") +
  theme_ggdist() +
  theme(legend.position = "none",
        panel.border = element_rect(colour = "grey78", fill=NA)) +
  labs(x="RR.level",
       y="")

#RR.slope histogram
c <- overall_change$slope_draws %>%
  ggplot() +
  geom_histogram(aes(x=estimate), fill="darkblue", colour="darkblue", alpha=0.3)+
  scale_fill_gradient(high="lightblue1",low="darkblue") +  
  scale_x_continuous(limits = c(0, 6)) +
  theme_ggdist() +
  theme(legend.position = "none",
        panel.border = element_rect(colour = "grey78", fill=NA)) +
  labs(x="RR.slope",
       y="")


#Correlation between RR.peak and RR.level
cor_rr_peak_rr_level <- round(cor(pluck(overall_change$peak_draws$estimate), pluck(overall_change$level_draws$estimate)), digits = 2)

#Correlation between RR.peak and RR.slope
cor_rr_peak_rr_slope <- round(cor(pluck(overall_change$peak_draws$estimate), pluck(overall_change$slope_draws$estimate)), digits = 2)

#Correlation between RR.level and RR.slope
cor_rr_level_rr_slope <- round(cor(pluck(overall_change$level_draws$estimate), pluck(overall_change$slope_draws$estimate)), digits = 2)


#plot of correlation between RR.peak and RR.level
d <- bind_cols(RR.peak=pluck(overall_change$peak_draws$estimate), 
          RR.level =pluck(overall_change$level_draws$estimate)) %>%
  ggplot(aes(y=RR.peak, x = RR.level)) +
  geom_hex() +
  geom_smooth(se=FALSE, colour="firebrick", method = "lm") +
  geom_text(aes(y=2.2, x=0.58, label=cor_rr_peak_rr_level), colour="firebrick")  +
  scale_fill_gradient(high="lightblue1",low="darkblue") +
  theme_ggdist() +
  theme(legend.position = "none",
        panel.border = element_rect(colour = "grey78", fill=NA))

#plot of correlation between RR.peak and RR.slope
e <- bind_cols(RR.peak=pluck(overall_change$peak_draws$estimate), 
          RR.slope =pluck(overall_change$slope_draws$estimate)) %>%
  ggplot(aes(y=RR.peak, x = RR.slope)) +
  geom_hex() +
  geom_smooth(se=FALSE, colour="firebrick", method = "lm") +
  geom_text(aes(y=2.1, x=0.5, label=cor_rr_peak_rr_slope), colour="firebrick")  +
  scale_x_continuous(limits = c(0, 6)) +
  scale_fill_gradient(high="lightblue1",low="darkblue") +
  theme_ggdist() +
  theme(legend.position = "none",
        panel.border = element_rect(colour = "grey78", fill=NA))

#plot of correlation between RR.level and RR.slope
f <- bind_cols(RR.level=pluck(overall_change$level_draws$estimate), 
          RR.slope =pluck(overall_change$slope_draws$estimate)) %>%
  ggplot(aes(y=RR.level, x = RR.slope)) +
  geom_hex() +
  geom_smooth(se=FALSE, colour="firebrick", method = "lm") +
  geom_text(aes(y=0.75, x=0.5, label=cor_rr_level_rr_slope), colour="firebrick")  +  
  scale_x_continuous(limits = c(0, 6)) +
  scale_fill_gradient(high="lightblue1",low="darkblue") +
  theme_ggdist() +
  theme(legend.position = "none",
        panel.border = element_rect(colour = "grey78", fill=NA))


(plot_spacer() + plot_spacer() + c) /
  (plot_spacer() + b + f) /
  (a + d + e)

ggsave(here("figures/pulmonary_cors.pdf"), width=8, height=8)

NA
NA
NA

7.5 Ward level pulmonary TB estimates

Plot the counterfactual at ward level


plot_counterfactual(model_data = mdata, model=m_pulmonary, outcome = inc_100k, population_denominator = population_without_inst_ship, 
                    grouping_var = ward, ward, re_formula= ~(1 + y_num*acf_period | ward))
  
ggsave(here("figures/s3.png"), width=12, height=12)

Summary of change in notifications at ward level

Calculate the counterfactual per ward


ward_pulmonary_counterf <- calculate_counterfactual(model_data = mdata, model=m_pulmonary, 
                                                    population_denominator = population_without_inst_ship,
                                                    grouping_var = ward, re_formula=~(1 + y_num*acf_period | ward))

ward_pulmonary_counterf$counter_post %>%
  mutate(across(c(cases_averted:cases_averted.upper, diff_inc100k:diff_inc100k.upper), number_format(accuracy = 0.1, big.mark = ","))) %>%
  mutate(across(c(rr_inc100k:rr_inc100k.upper), number_format(accuracy = 0.01))) %>%
  mutate(across(c(pct_change:pct_change.upper), percent, accuracy=0.1)) %>%
  datatable()

Overall counterfactual per ward


ward_pulmonary_counterf$counter_post_overall %>%
  mutate(across(c(cases_averted:cases_averted.upper), number_format(accuracy = 0.1, big.mark = ","))) %>%
  mutate(across(c(pct_change:pct_change.upper), percent, accuracy=0.1)) %>%
  datatable()

8. Extra-pulmonary TB notifications

Now we will model the extra-pulmonary TB notification rate. Struggling a bit with negative binomial model, so revert to Poisson.

8.1 Fit the model


m_extrapulmonary <- brm(
  cases ~ 1 + y_num*acf_period + (1 + y_num*acf_period | ward) + offset(log(population_without_inst_ship)),
                  data = mdata_extrapulmonary,
                  family = negbinomial(),
                  seed = 1234,
                  chains = 4, cores = 4,
                  prior = prior(normal(0,1000), class = Intercept) +
                          prior(gamma(0.01, 0.01), class = shape) +
                          prior(normal(0, 1), class = b) +
                          prior(exponential(1), class=sd) +
                          prior(lkj(2), class=cor))

summary(m_extrapulmonary)
plot(m_extrapulmonary)
pp_check(m_extrapulmonary, type='ecdf_overlay')

8.2 Summary of change

Summarise in plot

plot_counterfactual(model_data = overall_scaffold %>% filter(year<=1961), model=m_extrapulmonary, 
                    population_denominator = population_without_inst_ship, outcome=inc_100k_extrapulmonary, re_formula = NA)
  
ggsave(here("figures/s6.png"), width=10)

Summarise numerically.


overall_change_extrapulmonary <- summarise_change(model_data=overall_scaffold, model=m_extrapulmonary, 
                                   population_denominator=population_without_inst_ship, grouping_var=NULL, re_formula = NA)

#want to keep the summary estimates here
tokeep <- c("peak_summary", "level_summary", "slope_summary")

#summary measures in a table
overall_change_extrapulmonary %>%
  keep(names(.) %in% tokeep) %>%
  bind_rows() %>%
  mutate(across(c(estimate:.upper), number, accuracy=0.01)) %>%
  select(measure, everything()) %>%
  datatable()

8.3 Compared to counterfactual

Numbers of extra-pulmonary TB cases averted overall.


overall_ep_counterf <- calculate_counterfactual(model_data = mdata_extrapulmonary, model=m_extrapulmonary, 
                                               population_denominator = population_without_inst_ship)

overall_ep_counterf$counter_post %>%
  mutate(across(c(cases_averted:cases_averted.upper, diff_inc100k:diff_inc100k.upper), number_format(accuracy = 0.1, big.mark = ","))) %>%
  mutate(across(c(rr_inc100k:rr_inc100k.upper), number_format(accuracy = 0.01))) %>%
  mutate(across(c(pct_change:pct_change.upper), percent, accuracy=0.1)) %>%
  datatable()

Total extrapulmonary TB cases averted between 1958 and 1963


overall_ep_counterf$counter_post_overall %>%
  mutate(across(c(cases_averted:cases_averted.upper), number_format(accuracy = 0.1, big.mark = ","))) %>%
  mutate(across(c(pct_change:pct_change.upper), percent, accuracy=0.1)) %>%
  datatable()

8.4 Ward-level extra-pulmonary summaries

Ward-level extra-pulmonary estimates in graphical form.


plot_counterfactual(model_data = mdata_extrapulmonary, model=m_extrapulmonary, outcome = inc_100k, 
                    population_denominator = population_without_inst_ship, grouping_var = ward,re_formula =~(y_num*acf_period | ward), 
                    ward)
  
ggsave(here("figures/s4.png"), width=10, height=12)

Numerical summary.


ward_change_extrapulmonary <- summarise_change(model_data = mdata_extrapulmonary, model = m_extrapulmonary, 
                                population_denominator = population_without_inst_ship, grouping_var=ward,
                                re_formula = ~(y_num*acf_period | ward)) 

#want to keep the summary estimates here
tokeep <- c("peak_summary", "level_summary", "slope_summary")

#summary measures in a table
ward_change_extrapulmonary  %>%
  keep(names(.) %in% tokeep) %>%
  bind_rows() %>%
  mutate(across(c(estimate:.upper), number, accuracy=0.01)) %>%
  select(measure, everything()) %>%
  datatable()

9. Age-sex model

9.1 FIt the model

Fit the model

(Not rewritten the functions for this yet)


mdata_age_sex <- cases_by_age_sex %>%
  filter(tb_type=="Pulmonary") %>%
  mutate(acf_period = case_when(year %in% c(1950:1956) ~ "a. pre-acf",
                                year %in% c(1957) ~ "b. acf",
                                year %in% c(1958:1963) ~ "c. post-acf")) %>%
  mutate(year2 = year+0.5) %>%
  group_by(age, sex) %>%
  mutate(y_num = row_number()) %>%
  ungroup()

m_age_sex <- brm(
  cases ~ y_num + (acf_period)*(age*sex) + (acf_period:y_num)*(age*sex),
                  data = mdata_age_sex,
                  family = negbinomial(),
                  seed = 1234,
                  chains = 4, cores = 4, 
                  prior = prior(normal(0,1000), class = Intercept) +
                          prior(gamma(0.01, 0.01), class = shape) +
                          prior(normal(0, 1), class = b))

summary(m_age_sex)
plot(m_age_sex)
pp_check(m_age_sex, type='ecdf_overlay')

Summarise posterior


#posterior draws, and summarise
age_sex_summary <- mdata_age_sex %>%
  select(year, year2, y_num, acf_period, age, sex) %>%
  add_epred_draws(m_age_sex) %>%
  group_by(year2, acf_period, age, sex) %>%
  mean_qi() %>%
  mutate(acf_period = case_when(acf_period=="a. pre-acf" ~ "Before Intervention",
                                acf_period=="c. post-acf" ~ "Post Intervention"))

#create the counterfactual (no intervention), and summarise
age_sex_counterfact <- 
  tibble(year = mdata_age_sex$year,
         year2 = mdata_age_sex$year2,
         y_num = mdata_age_sex$y_num,
         age = mdata_age_sex$age,
         sex = mdata_age_sex$sex,
         acf_period = factor("a. pre-acf")) %>%
  add_epred_draws(m_age_sex) %>%
  group_by(year2, acf_period, age, sex) %>%
  mean_qi() %>%
  mutate(acf_period = case_when(acf_period=="a. pre-acf" ~ "Before Intervention",
                                acf_period=="c. post-acf" ~ "Post Intervention")) %>%
  ungroup() %>%
  mutate(age = case_when(age=="00_05" ~ "0 to 5y",
                         age=="06_15" ~ "06 to 15y",
                         age=="16_25" ~ "16 to 25y",
                         age=="26_35" ~ "26 to 35y",
                         age=="36_45" ~ "36 to 45y",
                         age=="46_55" ~ "46 to 55y",
                         age=="56_65" ~ "56 to 65y",
                         age=="65+" ~ "65 & up y")) %>%
  mutate(sex = case_when(sex== "M" ~ "Male",
                         sex== "F" ~ "Female")) 



age_sex_summary %>%
  ungroup() %>%
  mutate(age = case_when(age=="00_05" ~ "0 to 5y",
                         age=="06_15" ~ "06 to 15y",
                         age=="16_25" ~ "16 to 25y",
                         age=="26_35" ~ "26 to 35y",
                         age=="36_45" ~ "36 to 45y",
                         age=="46_55" ~ "46 to 55y",
                         age=="56_65" ~ "56 to 65y",
                         age=="65+" ~ "65 & up y")) %>%
  mutate(sex = case_when(sex== "M" ~ "Male",
                         sex== "F" ~ "Female")) %>%
  ggplot() +
  geom_ribbon(aes(ymin=.epred.lower, ymax=.epred.upper, x=year2, group = acf_period, fill=acf_period), alpha=0.5) +
  geom_ribbon(data = age_sex_counterfact %>% filter(year>=1956), 
              aes(ymin=.epred.lower, ymax=.epred.upper, x=year2, fill="Counterfactual"), alpha=0.5) +
  geom_line(data = age_sex_counterfact %>% filter(year>=1956), 
              aes(y=.epred, x=year2, colour="Counterfactual")) +
  geom_line(aes(y=.epred, x=year2, group=acf_period,  colour=acf_period)) +
  geom_point(data = mdata_age_sex %>%
  ungroup() %>%
  mutate(age = case_when(age=="00_05" ~ "0 to 5y",
                         age=="06_15" ~ "06 to 15y",
                         age=="16_25" ~ "16 to 25y",
                         age=="26_35" ~ "26 to 35y",
                         age=="36_45" ~ "36 to 45y",
                         age=="46_55" ~ "46 to 55y",
                         age=="56_65" ~ "56 to 65y",
                         age=="65+" ~ "65 & up y")) %>%
  mutate(sex = case_when(sex== "M" ~ "Male",
                         sex== "F" ~ "Female")) , aes(y=cases, x=year2, shape=acf_period), size=2) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  ggh4x::facet_grid2(age~sex, scales = "free_y", independent = "y") +
  theme_ggdist() +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels,
                     guide = guide_axis(angle = 90)) +
  scale_fill_manual(values = c("#DE0D92", "grey50", "#4D6CFA") , name="") +
  scale_colour_manual(values = c("#DE0D92", "grey50", "#4D6CFA") , name="") +
  scale_shape_discrete(name="") +
  labs(
    x = "Year",
    y = "Case notifications (n)",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)"
  ) +
  theme(legend.position = "bottom",
        panel.border = element_rect(colour = "grey78", fill=NA),
        title = element_text(size=14),
        axis.text = element_text(size=14),
        legend.text = element_text(size=12)) +
  guides(shape="none")
  
ggsave(here("figures/s7.png"), height=10)

9.2 Summary of impact of intervention

(This all needs tidying up and checking - to do!)

  1. percentage increase in CNR, from 1956 to 1957 (i.e. immediate ACF effect)

nd <- mdata_age_sex %>%
  filter(year %in% c(1956:1957)) %>%
  select(acf_period, y_num, age, sex)


age_sex_impact_out <- 
  add_epred_draws(m_age_sex,
                newdata=nd) %>%
  ungroup() %>%
  select(acf_period, .epred, age, sex) %>%
  pivot_wider(names_from = acf_period,
              values_from = .epred,
              values_fn = list) %>%
  unnest() %>%
  rename(pre_epred = 3,
         post_epred = 4) %>%
  mutate(acf_diff = post_epred-pre_epred,
         acf_rr = post_epred/pre_epred) %>%
  group_by(age, sex) %>%
  mean_qi(acf_diff, acf_rr) 

age_sex_impact_out %>%
  mutate_if(is.double, ~ scales::number(x = ., accuracy = 0.01, big.mark = ",")) %>%
  datatable()
  
f3a <- age_sex_impact_out %>%
  mutate(sex = case_when(sex=="M" ~ "Male",
                         sex=="F" ~ "Female")) %>%
  mutate(age = case_when(age=="00_05" ~ "0 to 5y",
                         age=="06_15" ~ "06 to 15y",
                         age=="16_25" ~ "16 to 25y",
                         age=="26_35" ~ "26 to 35y",
                         age=="36_45" ~ "36 to 45y",
                         age=="46_55" ~ "46 to 55y",
                         age=="56_65" ~ "56 to 65y",
                         age=="65+" ~ "65 & up y")) %>%
  ggplot() +
  geom_pointrange(aes(y=acf_rr, ymin=acf_rr.lower, ymax=acf_rr.upper, group=sex, 
                      x=age,
                      colour = sex),
                  position = position_dodge(width = 0.25)) +
  geom_hline(aes(yintercept=1), linetype=2) +
  scale_colour_manual(values = c("purple", "darkorange"), name="") +
  labs(x="",
       y="Relative notifications (95% UI)\nACF (1957) vs. Before ACF (1956)") +
  theme_ggdist() +
  theme(legend.position = "bottom",
        panel.border = element_rect(colour = "grey78", fill=NA))
  
  
  1. Change from pre-ACF period (1956), to first year post-ACF (1958)

nd <- mdata_age_sex %>%
  filter(year %in% c(1956,1958)) %>%
  select(acf_period, y_num, age, sex)

#Do it with calculating incidence, then sumamrising.
age_sex_impact2 <-add_epred_draws(m_age_sex,
                newdata=nd) %>%
  ungroup() %>%
  select(acf_period, .epred, age, sex) %>%
  pivot_wider(names_from = acf_period,
              values_from = .epred,
              values_fn = list) %>%
  unnest() %>%
  rename(pre_epred = 3,
        post_epred = 4) %>%
  mutate(acf_diff = post_epred-pre_epred,
         acf_rr = post_epred/pre_epred) %>%
  group_by(age, sex) %>%
  mean_qi(acf_diff, acf_rr) 

age_sex_impact2 %>%
  mutate_if(is.double, ~ scales::number(x = ., accuracy = 0.01, big.mark = ",")) %>%
  datatable()

f3b <- age_sex_impact2 %>%  
  mutate(sex = case_when(sex=="M" ~ "Male",
                         sex=="F" ~ "Female")) %>%
  mutate(age = case_when(age=="00_05" ~ "0 to 5y",
                         age=="06_15" ~ "06 to 15y",
                         age=="16_25" ~ "16 to 25y",
                         age=="26_35" ~ "26 to 35y",
                         age=="36_45" ~ "36 to 45y",
                         age=="46_55" ~ "46 to 55y",
                         age=="56_65" ~ "56 to 65y",
                         age=="65+" ~ "65 & up y")) %>%
  ggplot() +
  geom_pointrange(aes(y=acf_rr, ymin=acf_rr.lower, ymax=acf_rr.upper, group=sex, 
                      x=age,
                      colour = sex),
                  position = position_dodge(width = 0.25)) +
  geom_hline(aes(yintercept=1), linetype=2) +
  scale_colour_manual(values = c("purple", "darkorange"), name="") +
  labs(x="",
       y="Relative notifications (95% UI)\nACF (1958) vs. Before ACF (1956)") +
  theme_ggdist() +
  theme(legend.position = "bottom",
        panel.border = element_rect(colour = "grey78", fill=NA))
  1. Change in slope (i.e. difference in mean annual case notification rate pre-Intervention vs. post-intervention, by ward)

age_sex_impact3 <- mdata_age_sex %>%
  select(year, year2, y_num, acf_period, cases, age, sex) %>%
  filter(year!=1957) %>%
  add_epred_draws(m_age_sex) %>%
  group_by(year, age, sex, acf_period) %>%
  mean_qi(.epred) %>%
  ungroup() %>%
  mutate(n_years = length(year), .by=acf_period) %>%
  summarise(pct_change_epred_overall = (((last(.epred) - first(.epred))/first(.epred))),
            pct_change_lower_overall = (((last(.lower) - first(.lower))/first(.lower))),
            pct_change_upper_overall = (((last(.upper) - first(.upper))/first(.upper))),
    
            pct_change_epred_annual = (((last(.epred) - first(.epred))/first(.epred))/n_years),
            pct_change_lower_annual = (((last(.lower) - first(.lower))/first(.lower))/n_years),
            pct_change_upper_annual = (((last(.upper) - first(.upper))/first(.upper))/n_years),
            .by = c(acf_period, age, sex)) %>%
  distinct()


age_sex_impact3 %>%
  mutate_if(is.double, percent) %>%
  datatable()

f3c <- age_sex_impact3 %>%
  mutate(sex = case_when(sex=="M" ~ "Male",
                         sex=="F" ~ "Female")) %>%
  mutate(age = case_when(age=="00_05" ~ "0 to 5y",
                         age=="06_15" ~ "06 to 15y",
                         age=="16_25" ~ "16 to 25y",
                         age=="26_35" ~ "26 to 35y",
                         age=="36_45" ~ "36 to 45y",
                         age=="46_55" ~ "46 to 55y",
                         age=="56_65" ~ "56 to 65y",
                         age=="65+" ~ "65 & up y")) %>%
  ggplot() +
    geom_hline(aes(yintercept=0), linetype=2) +
    geom_pointrange(aes(y=pct_change_epred_annual, ymin=pct_change_lower_annual, ymax=pct_change_upper_annual, group=acf_period, 
                      x=age,
                      colour = acf_period), size=0.1) +
  scale_y_continuous(labels =percent) +
  facet_grid(.~sex) +
  coord_flip() +
  scale_colour_manual(values = c("#DE0D92", "#4D6CFA")) +
  labs(x="",
       y="Mean annual rate of change in case notification rate (95% UI)\n Before ACF (1950-1956) vs. after ACF (1958-1963)",
       colour="") +
  theme_ggdist() +
  theme(panel.border = element_rect(colour = "grey78", fill=NA))

f3c

9.3 Compared to counterfactual


counterfact_age_sex <-
      add_epred_draws(object = m_age_sex,
                      newdata = mdata_age_sex %>%
                                    select(year, year2, y_num, age, sex) %>%
                                    mutate(acf_period = "a. pre-acf")) %>%
      filter(year>1957) %>%
      select(year, age, sex, .draw, .epred_counterf = .epred)
  
#Calcuate incidence per draw, then summarise.
  post_change_age_sex <-
      add_epred_draws(object = m_age_sex,
                      newdata = mdata_age_sex %>%
                                    select(year, year2, y_num, age, sex, acf_period)) %>%
      filter(year>1957) %>%
      ungroup() %>%
      select(year, age, sex, .draw, .epred) 
  
  #for the overall period
counterfact_overall_age_sex <-
      add_epred_draws(object = m_age_sex,
                      newdata = mdata_age_sex %>%
                                    select(year, year2, y_num, age, sex) %>%
                                    mutate(acf_period = "a. pre-acf")) %>%
      filter(year>1957) %>%
      select(age, sex, .draw, .epred)  %>%
      group_by(age, sex, .draw) %>%
      summarise(.epred_counterf = sum(.epred)) %>%
      mutate(year = "Overall (1958-1963)")
  
  #Calcuate incidence per draw, then summarise.
  post_change_overall_age_sex <-
      add_epred_draws(object = m_age_sex,
                      newdata = mdata_age_sex %>%
                                    select(year, year2, y_num, age, sex, acf_period)) %>%
      filter(year>1957) %>%
      select(age, sex, .draw, .epred) %>%
      group_by(.draw, age, sex) %>%
      summarise(.epred = sum(.epred)) 
  
  

left_join(counterfact_age_sex, post_change_age_sex) %>%
    mutate(cases_averted = .epred_counterf-.epred,
           pct_change = (.epred - .epred_counterf)/.epred_counterf) %>%
    group_by(year, age, sex) %>%
    mean_qi(cases_averted, pct_change) %>%
    ungroup() %>%
  datatable()

counter_post_overall_age_sex <-
  left_join(counterfact_overall_age_sex, post_change_overall_age_sex) %>%
    mutate(cases_averted = .epred_counterf-.epred,
           pct_change = (.epred - .epred_counterf)/.epred_counterf) %>%
    group_by(age, sex) %>%
    mean_qi(cases_averted, pct_change) %>%
    ungroup() %>%
    mutate(year = "Overall (1958-1963)") 

age_sex_txt <- counter_post_overall_age_sex %>%
  mutate(across(c(cases_averted:cases_averted.upper), number_format(accuracy = 0.1, big.mark = ","))) %>%
  mutate(across(c(pct_change:pct_change.upper), percent, accuracy=0.1)) %>%
  transmute(year = as.character(year),
            sex = sex,
            age = age,
            cases_averted = glue::glue("{cases_averted}\n({cases_averted.lower} to {cases_averted.upper})"),
            pct_change = glue::glue("{pct_change}\n({pct_change.lower} to {pct_change.upper})"))


age_sex_txt %>% datatable()

f3d <- counter_post_overall_age_sex %>% 
  mutate(sex = case_when(sex=="M" ~ "Male",
                         sex=="F" ~ "Female")) %>%
  mutate(age = case_when(age=="00_05" ~ "0 to 5y",
                         age=="06_15" ~ "06 to 15y",
                         age=="16_25" ~ "16 to 25y",
                         age=="26_35" ~ "26 to 35y",
                         age=="36_45" ~ "36 to 45y",
                         age=="46_55" ~ "46 to 55y",
                         age=="56_65" ~ "56 to 65y",
                         age=="65+" ~ "65 & up y")) %>%
  ggplot() +
  geom_pointrange(aes(x = age, y=cases_averted, ymin=cases_averted.lower, ymax=cases_averted.upper, colour=sex)) + 
  facet_grid(.~sex) +
  coord_flip() +
  scale_colour_manual(values = c("purple", "darkorange"), name="") +
  scale_y_continuous(labels = comma) +
  labs(x="",
       y="Number (95% UI) of TB cases averted (1958-1963)",
       colour="") +
  theme_ggdist() +
  theme(panel.border = element_rect(colour = "grey78", fill=NA),
        legend.position = "none")

f3d

Join together for Figure 2.


(f3a + f3b) / (f3c + f3d) + plot_annotation(tag_levels = "A")

ggsave(here("figures/f3.png"), width = 12)

mdata_age_sex

LS0tCnRpdGxlOiAiR2xhc2dvdyBUQiBBQ0YiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCiMjIyAxLiBMaWJyYXJpZXMgYW5kIGZ1bmN0aW9ucwoKIyMjIyAxLjEgTGlicmFyaWVzCgpMb2FkIHRoZSByZXF1aXJlZCBsaWJyYXJpZXMuCgpgYGB7ciwgbWVzc2FnZT1GLCB3YXJuaW5nPUZ9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHNmKQpsaWJyYXJ5KGhlcmUpCmxpYnJhcnkocmVhZHhsKQpsaWJyYXJ5KHNjYWxlcykKbGlicmFyeShEVCkKbGlicmFyeShicm1zKQpsaWJyYXJ5KHRpZHliYXllcykKbGlicmFyeShwYXRjaHdvcmspCmxpYnJhcnkobWFyZ2luYWxlZmZlY3RzKQpsaWJyYXJ5KGdncmVwZWwpCmxpYnJhcnkoc2NpY28pCmxpYnJhcnkoZ2dkZW5zaXR5KQpsaWJyYXJ5KGdncHVicikKbGlicmFyeSh1bml0cykKI2xpYnJhcnkoZ2dzbikKCmBgYAoKIyMjIyAxLjIgSGVscGVyIGZ1bmN0aW9ucwoKRnVuY3Rpb25zIHRoYXQgd2Ugd2lsbCB1c2UgdGhyb3VnaG91dCB0aGUgc2NyaXB0CgpgYGB7cn0KI2xhYmVsbGVyIGZvciB5ZWFycwp5ZWFyX2xhYmVscyA8LSBjKDE5NTA6MTk2MykKCiNUaGUgR2xhc2dvdyBtYXNzIG1pbnV0dXJlIGNoZXN0IFgtcmF5IGNhbXBhaWduIGhhcHBlbmVkIGJldHdlZW4gMTF0aCBNYXJjaCBhbmQgMTJ0aCBBcHJpbCAxOTU3CiNTZWdtZW50IGZvciBncmFwaHMgdG8gbWF0Y2ggQUNGIHBlcmlvZAphY2Zfc3RhcnQgPC0gZGVjaW1hbF9kYXRlKHltZCgiMTk1Ny0wMy0xMSIpKQphY2ZfZW5kIDwtIGRlY2ltYWxfZGF0ZSh5bWQoIjE5NTctMDQtMTIiKSkKCgpgYGAKCkZ1bmN0aW9uIGZvciBjb3VudGVyZmFjdHVhbCBwbG90cwoKYGBge3J9CgoKcGxvdF9jb3VudGVyZmFjdHVhbCA8LSBmdW5jdGlvbihtb2RlbF9kYXRhLCBtb2RlbCwgcG9wdWxhdGlvbl9kZW5vbWluYXRvciwgb3V0Y29tZSwgZ3JvdXBpbmdfdmFyPU5VTEwsIHJlX2Zvcm11bGEsLi4uKXsKICAKICAjbGFiZWxsZXIgZm9yIHllYXJzCiAgeWVhcl9sYWJlbHMgPC0gYygxOTUwOjE5NjMpCgogICNUaGUgR2xhc2dvdyBtYXNzIG1pbnV0dXJlIGNoZXN0IFgtcmF5IGNhbXBhaWduIGhhcHBlbmVkIGJldHdlZW4gMTF0aCBNYXJjaCBhbmQgMTJ0aCBBcHJpbCAxOTU3CiAgI1NlZ21lbnQgZm9yIGdyYXBocyB0byBtYXRjaCBBQ0YgcGVyaW9kCiAgYWNmX3N0YXJ0IDwtIGRlY2ltYWxfZGF0ZSh5bWQoIjE5NTctMDMtMTEiKSkKICBhY2ZfZW5kIDwtIGRlY2ltYWxfZGF0ZSh5bWQoIjE5NTctMDQtMTIiKSkKCiAgc3VtbWFyeSA8LSB7e21vZGVsX2RhdGF9fSAlPiUKICAgIHNlbGVjdCh5ZWFyLCB5ZWFyMiwgeV9udW0sIGFjZl9wZXJpb2QsIHt7cG9wdWxhdGlvbl9kZW5vbWluYXRvcn19LCB7e291dGNvbWV9fSwge3tncm91cGluZ192YXJ9fSkgJT4lCiAgICBhZGRfZXByZWRfZHJhd3Moe3ttb2RlbH19LCByZV9mb3JtdWxhPXt7cmVfZm9ybXVsYX19KSAlPiUKICAgIGdyb3VwX2J5KHllYXIyLCBhY2ZfcGVyaW9kLCB7e2dyb3VwaW5nX3Zhcn19KSAlPiUKICAgIG1lYW5fcWkoKSAlPiUKICAgIG11dGF0ZSguZXByZWRfaW5jID0gLmVwcmVkL3t7cG9wdWxhdGlvbl9kZW5vbWluYXRvcn19KjEwMDAwMCwKICAgICAgICAgIC5lcHJlZF9pbmMubG93ZXIgPSAuZXByZWQubG93ZXIve3twb3B1bGF0aW9uX2Rlbm9taW5hdG9yfX0qMTAwMDAwLAogICAgICAgICAgLmVwcmVkX2luYy51cHBlciA9IC5lcHJlZC51cHBlci97e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSoxMDAwMDApICU+JQogICAgbXV0YXRlKGFjZl9wZXJpb2QgPSBjYXNlX3doZW4oYWNmX3BlcmlvZD09ImEuIHByZS1hY2YiIH4gIkJlZm9yZSBJbnRlcnZlbnRpb24iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWNmX3BlcmlvZD09ImMuIHBvc3QtYWNmIiB+ICJQb3N0IEludGVydmVudGlvbiIpKQoKCgogICNjcmVhdGUgdGhlIGNvdW50ZXJmYWN0dWFsIChubyBpbnRlcnZlbnRpb24pLCBhbmQgc3VtbWFyaXNlCiAgCiAgY291bnRlcmZhY3QgPC0KICAgIGFkZF9lcHJlZF9kcmF3cyhvYmplY3QgPSB7e21vZGVsfX0sCiAgICAgICAgICAgICAgICAgICAgbmV3ZGF0YSA9IHt7bW9kZWxfZGF0YX19ICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KHllYXIsIHllYXIyLCB5X251bSwge3twb3B1bGF0aW9uX2Rlbm9taW5hdG9yfX0sIHt7Z3JvdXBpbmdfdmFyfX0sIHt7b3V0Y29tZX19KSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShhY2ZfcGVyaW9kID0gImEuIHByZS1hY2YiKSwgcmVfZm9ybXVsYT17e3JlX2Zvcm11bGF9fSkgJT4lCiAgICBncm91cF9ieSh5ZWFyMiwgYWNmX3BlcmlvZCwge3tncm91cGluZ192YXJ9fSkgJT4lCiAgICBtZWFuX3FpKCkgJT4lCiAgICBtdXRhdGUoLmVwcmVkX2luYyA9IC5lcHJlZC97e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSoxMDAwMDAsCiAgICAgICAgIC5lcHJlZF9pbmMubG93ZXIgPSAuZXByZWQubG93ZXIve3twb3B1bGF0aW9uX2Rlbm9taW5hdG9yfX0qMTAwMDAwLAogICAgICAgICAuZXByZWRfaW5jLnVwcGVyID0gLmVwcmVkLnVwcGVyL3t7cG9wdWxhdGlvbl9kZW5vbWluYXRvcn19KjEwMDAwMCkgJT4lCiAgICBtdXRhdGUoYWNmX3BlcmlvZCA9IGNhc2Vfd2hlbihhY2ZfcGVyaW9kPT0iYS4gcHJlLWFjZiIgfiAiQmVmb3JlIEludGVydmVudGlvbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWNmX3BlcmlvZD09ImMuIHBvc3QtYWNmIiB+ICJQb3N0IEludGVydmVudGlvbiIpKQogIAoKCiAgI3Bsb3QgdGhlIGludGVydmVudGlvbiBlZmZlY3QKcCA8LSBzdW1tYXJ5ICU+JQogICAgZHJvcGxldmVscygpICU+JQogICAgZ2dwbG90KCkgKwogICAgZ2VvbV9yaWJib24oYWVzKHltaW49LmVwcmVkX2luYy5sb3dlciwgeW1heD0uZXByZWRfaW5jLnVwcGVyLCB4PXllYXIyLCBncm91cCA9IGFjZl9wZXJpb2QsIGZpbGw9YWNmX3BlcmlvZCksIGFscGhhPTAuNSkgKwogICAgZ2VvbV9yaWJib24oZGF0YSA9IGNvdW50ZXJmYWN0ICU+JSBmaWx0ZXIoeWVhcj49MTk1NiksIAogICAgICAgICAgICAgICAgYWVzKHltaW49LmVwcmVkX2luYy5sb3dlciwgeW1heD0uZXByZWRfaW5jLnVwcGVyLCB4PXllYXIyLCBmaWxsPSJDb3VudGVyZmFjdHVhbCIpLCBhbHBoYT0wLjUpICsKICAgIGdlb21fbGluZShkYXRhID0gY291bnRlcmZhY3QgJT4lIGZpbHRlcih5ZWFyPj0xOTU2KSwgCiAgICAgICAgICAgICAgYWVzKHk9LmVwcmVkX2luYywgeD15ZWFyMiwgY29sb3VyPSJDb3VudGVyZmFjdHVhbCIpKSArCiAgICBnZW9tX2xpbmUoYWVzKHk9LmVwcmVkX2luYywgeD15ZWFyMiwgZ3JvdXA9YWNmX3BlcmlvZCwgIGNvbG91cj1hY2ZfcGVyaW9kKSkgKwogICAgZ2VvbV9wb2ludChkYXRhID0ge3ttb2RlbF9kYXRhfX0sIGFlcyh5PXt7b3V0Y29tZX19LCB4PXllYXIyLCBzaGFwZT1hY2ZfcGVyaW9kKSwgc2l6ZT0yKSArCiAgICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9lbmQpLCBsaW5ldHlwZT0zKSArCiAgICB0aGVtZV9nZ2Rpc3QoKSArCiAgICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzPWNvbW1hLCBsaW1pdHMgPSBjKDAsTkEpKSArCiAgICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0geWVhcl9sYWJlbHMsCiAgICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0geWVhcl9sYWJlbHMpICsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiNERTBEOTIiLCAiZ3JleTUwIiwgIiM0RDZDRkEiKSAsIG5hbWU9IiIsIG5hLnRyYW5zbGF0ZSA9IEYpICsKICAgIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiI0RFMEQ5MiIsICJncmV5NTAiLCAiIzRENkNGQSIpICwgbmFtZT0iIiwgbmEudHJhbnNsYXRlID0gRikgKwogICAgc2NhbGVfc2hhcGVfZGlzY3JldGUobmFtZT0iIiwgbmEudHJhbnNsYXRlID0gRikgKwogICAgbGFicygKICAgICAgeCA9ICJZZWFyIiwKICAgICAgeSA9ICJDYXNlIG5vdGlmaWNhdGlvbiByYXRlIChwZXIgMTAwLDAwMCkiLAogICAgICBjYXB0aW9uID0gIk1hc3MgbWluaWF0dXJlIFgtcmF5IGNhbXBhaWduIHBlcmlvZCBiZXR3ZWVuIGRhc2hlZCBsaW5lcyAoMTF0aCBNYXJjaC0xMnRoIEFwcmlsIDE5NTcpIgogICAgKSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleTc4IiwgZmlsbD1OQSksCiAgICAgICAgICB0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9OCksCiAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplPTgsIGFuZ2xlID0gOTAsIGhqdXN0PTEsIHZqdXN0PTAuNSksCiAgICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTgpKSArCiAgICBndWlkZXMoc2hhcGU9Im5vbmUiKQoKICAgIGZhY2V0X3ZhcnMgPC0gdmFycyguLi4pCgogIGlmIChsZW5ndGgoZmFjZXRfdmFycykgIT0gMCkgewogICAgcCA8LSBwICsgZmFjZXRfd3JhcChmYWNldF92YXJzKQogIH0KICBwCgp9CgpgYGAKCkZ1bmN0aW9uIGZvciBjYWxjdWxhdGluZyAgbWVhc3VyZXMgb2YgY2hhbmdlIG92ZXIgdGltZSAoUlIucGVhaywgUlIubGV2ZWwsIFJSLnNsb3BlKQoKCmBgYHtyfQoKc3VtbWFyaXNlX2NoYW5nZSA8LSBmdW5jdGlvbihtb2RlbF9kYXRhLCBtb2RlbCwgcG9wdWxhdGlvbl9kZW5vbWluYXRvciwgZ3JvdXBpbmdfdmFyID0gTlVMTCwgcmVfZm9ybXVsYSA9IE5VTEwpIHsKICAKICAjZnVuY3Rpb25zIGZvciBjYWxjdWxhdGluZyBSUi5wZWFrCiAgI2kuZS4gcmVsYXRpdmUgY2FzZSBub3RpZmljYXRpb24gcmF0ZSBpbiAxOTU3IHZzLiBjb3VudGVyZmFjdHVhbCB0cmVuZCBmb3IgMTk1NwogIAogIGdyb3VwaW5nX3ZhciA8LSBlbnF1byhncm91cGluZ192YXIpCiAgCiAgaWYgKCFpcy5udWxsKHt7Z3JvdXBpbmdfdmFyfX0pKSB7CiAgICAKICAgICNtYWtlIHRoZSBwcmVkaWN0aW9uIG1hdHJpeCwgY29uZGl0aW9uYWwgb24gd2hldGhlciB3ZSB3YW50IHJhbmRvbSBlZmZlY3RzIGluY2x1ZGVkIG9yIG5vdC4KICAgIG91dCA8LSBjcm9zc2luZyh7e21vZGVsX2RhdGF9fSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICBzZWxlY3Qoe3twb3B1bGF0aW9uX2Rlbm9taW5hdG9yfX0sIHlfbnVtLCAhIWdyb3VwaW5nX3ZhcikgJT4lCiAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXIoeV9udW0gPT0gOCksCiAgICAgICAgICAgICAgICAgICAgYWNmX3BlcmlvZCA9IGMoImEuIHByZS1hY2YiLCAiYi4gYWNmIikKICAgICkKICB9IGVsc2UgewogICAgCiAgICBvdXQgPC0gY3Jvc3Npbmcoe3ttb2RlbF9kYXRhfX0gJT4lIAogICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KHt7cG9wdWxhdGlvbl9kZW5vbWluYXRvcn19LCB5X251bSkgJT4lCiAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXIoeV9udW0gPT0gOCksCiAgICAgICAgICAgICAgICAgICAgYWNmX3BlcmlvZCA9IGMoImEuIHByZS1hY2YiLCAiYi4gYWNmIikKICAgICkKICB9CiAgCiAgcGVha19kcmF3cyA8LSBhZGRfZXByZWRfZHJhd3MobmV3ZGF0YSA9IG91dCwKICAgICAgICAgICAgICAgICAgb2JqZWN0ID0ge3ttb2RlbH19LAogICAgICAgICAgICAgICAgICByZV9mb3JtdWxhID0ge3tyZV9mb3JtdWxhfX0pICU+JQogICAgbXV0YXRlKGVwcmVkX2NuciA9IC5lcHJlZC9wb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwKjEwMDAwMCkgJT4lCiAgICBncm91cF9ieSguZHJhdywgISFncm91cGluZ192YXIpICU+JQogICAgc3VtbWFyaXNlKGVzdGltYXRlID0gbGFzdChlcHJlZF9jbnIpL2ZpcnN0KGVwcmVkX2NucikpICU+JQogICAgdW5ncm91cCgpICU+JQogICAgbXV0YXRlKG1lYXN1cmUgPSAiUlIucGVhayIpCiAgCiAgcGVha19zdW1tYXJ5IDwtIHBlYWtfZHJhd3MgJT4lCiAgICBncm91cF9ieSghIWdyb3VwaW5nX3ZhcikgJT4lCiAgICBtZWFuX3FpKGVzdGltYXRlKSAlPiUKICAgIG11dGF0ZShtZWFzdXJlID0gIlJSLnBlYWsiKQogIAogIAogICNmdW5jdGlvbnMgZm9yIGNhbGN1bGF0aW5nIFJSLnN0ZXAKICAjaS5lLiByZWxhdGl2ZSBjYXNlIG5vdGlmaWNhdGlvbiByYXRlIGluIDE5NTggdnMuIGNvdW50ZXJmYWN0dWFsIHRyZW5kIGZvciAxOTU4CiAgCiAgICBpZiAoIWlzLm51bGwoe3tncm91cGluZ192YXJ9fSkpIHsKICAgIG91dDIgPC0gY3Jvc3Npbmcoe3ttb2RlbF9kYXRhfX0gJT4lIAogICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KHt7cG9wdWxhdGlvbl9kZW5vbWluYXRvcn19LCB5X251bSwgISFncm91cGluZ192YXIpICU+JQogICAgICAgICAgICAgICAgICAgICAgZmlsdGVyKHlfbnVtID09IDkpLAogICAgICAgICAgICAgICAgICAgIGFjZl9wZXJpb2QgPSBjKCJhLiBwcmUtYWNmIiwgImMuIHBvc3QtYWNmIikKICAgICkKICB9IGVsc2UgewogICAgCiAgICBvdXQyIDwtIGNyb3NzaW5nKHt7bW9kZWxfZGF0YX19ICU+JSAKICAgICAgICAgICAgICAgICAgICAgIHNlbGVjdCh7e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSwgeV9udW0pICU+JQogICAgICAgICAgICAgICAgICAgICAgZmlsdGVyKHlfbnVtID09IDkpLAogICAgICAgICAgICAgICAgICAgIGFjZl9wZXJpb2QgPSBjKCJhLiBwcmUtYWNmIiwgImMuIHBvc3QtYWNmIikKICAgICkKICB9CiAgCiAgICBsZXZlbF9kcmF3cyA8LSBhZGRfZXByZWRfZHJhd3MobmV3ZGF0YSA9IG91dDIsCiAgICAgICAgICAgICAgICAgIG9iamVjdCA9IHt7bW9kZWx9fSwKICAgICAgICAgICAgICAgICAgcmVfZm9ybXVsYSA9IHt7cmVfZm9ybXVsYX19KSAlPiUKICAgIGFycmFuZ2UoeV9udW0sIC5kcmF3KSAlPiUKICAgIG11dGF0ZShlcHJlZF9jbnIgPSAuZXByZWQvcG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCoxMDAwMDApICU+JQogICAgZ3JvdXBfYnkoLmRyYXcsICEhZ3JvdXBpbmdfdmFyKSAlPiUKICAgIHN1bW1hcmlzZShlc3RpbWF0ZSA9IGxhc3QoZXByZWRfY25yKS9maXJzdChlcHJlZF9jbnIpKSAlPiUKICAgIHVuZ3JvdXAoKSAlPiUKICAgIG11dGF0ZShtZWFzdXJlID0gIlJSLmxldmVsIikKICAKICBsZXZlbF9zdW1tYXJ5IDwtIGxldmVsX2RyYXdzICU+JQogICAgZ3JvdXBfYnkoISFncm91cGluZ192YXIpICU+JQogICAgbWVhbl9xaShlc3RpbWF0ZSkgJT4lCiAgICBtdXRhdGUobWVhc3VyZSA9ICJSUi5sZXZlbCIpCiAgICAKICAgIAogICNmdW5jdGlvbnMgZm9yIGNhbGN1bGF0aW5nIFJSLnNsb3BlCiAgI2kuZS4gcmVsYXRpdmUgY2hhbmdlIGluIGNhc2Ugbm90aWZpY2F0aW9uIHJhdGUgaW4gMTk1OC0xOTYzIHZzLiBjb3VudGVyZmFjdHVhbCB0cmVuZCBmb3IgMTk1OS0xOTYzCiAgCiAgICBpZiAoIWlzLm51bGwoe3tncm91cGluZ192YXJ9fSkpIHsKICAgIG91dDMgPC0gY3Jvc3Npbmcoe3ttb2RlbF9kYXRhfX0gJT4lIAogICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KHt7cG9wdWxhdGlvbl9kZW5vbWluYXRvcn19LCB5X251bSwgISFncm91cGluZ192YXIpICU+JQogICAgICAgICAgICAgICAgICAgICAgZmlsdGVyKHlfbnVtICVpbiUgYyg5LDE0KSksCiAgICAgICAgICAgICAgICAgICAgYWNmX3BlcmlvZCA9IGMoImEuIHByZS1hY2YiLCAiYy4gcG9zdC1hY2YiKQogICAgKQogIH0gZWxzZSB7CiAgICAKICAgIG91dDMgPC0gY3Jvc3Npbmcoe3ttb2RlbF9kYXRhfX0gJT4lIAogICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KHt7cG9wdWxhdGlvbl9kZW5vbWluYXRvcn19LCB5X251bSkgJT4lCiAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXIoeV9udW0gJWluJSBjKDksMTQpKSwKICAgICAgICAgICAgICAgICAgICBhY2ZfcGVyaW9kID0gYygiYS4gcHJlLWFjZiIsICJjLiBwb3N0LWFjZiIpCiAgICApCiAgfQogIAogICAgc2xvcGVfZHJhd3MgPC0gYWRkX2VwcmVkX2RyYXdzKG5ld2RhdGEgPSBvdXQzLAogICAgICAgICAgICAgICAgICBvYmplY3QgPSB7e21vZGVsfX0sCiAgICAgICAgICAgICAgICAgIHJlX2Zvcm11bGEgPSB7e3JlX2Zvcm11bGF9fSkgJT4lCiAgICAgICAgYXJyYW5nZSh5X251bSkgJT4lCiAgICAgICAgdW5ncm91cCgpICU+JQogICAgICAgIG11dGF0ZShlcHJlZF9jbnIgPSAuZXByZWQvcG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCoxMDAwMDApICU+JQogICAgICAgIGdyb3VwX2J5KC5kcmF3LCBhY2ZfcGVyaW9kLCAhIWdyb3VwaW5nX3ZhcikgJT4lCiAgICAgICAgc3VtbWFyaXNlKHNsb3BlID0gKGxhc3QoZXByZWRfY25yKSAtIGZpcnN0KGVwcmVkX2NucikpIC8gKGxhc3QoeV9udW0pLWZpcnN0KHlfbnVtKSkpICU+JQogICAgICAgIHVuZ3JvdXAoKSAlPiUKICAgICAgICBncm91cF9ieSguZHJhdywgISFncm91cGluZ192YXIpICU+JQogICAgICAgIHN1bW1hcmlzZShlc3RpbWF0ZSA9IGxhc3Qoc2xvcGUpL2ZpcnN0KHNsb3BlKSkgJT4lCiAgICAgICAgbXV0YXRlKG1lYXN1cmUgPSAiUlIuc2xvcGUiKQogIAogIHNsb3BlX3N1bW1hcnkgPC0gc2xvcGVfZHJhd3MgJT4lCiAgICAgZ3JvdXBfYnkoISFncm91cGluZ192YXIpICU+JQogICAgICBtZWRpYW5fcWkoZXN0aW1hdGUpICU+JQogICAgICBtdXRhdGUobWVhc3VyZSA9ICJSUi5zbG9wZSIpCiAgICAKICAjZ2F0aGVyIGFsbCB0aGUgcmVzdWx0cyBpbnRvIGEgbmFtZWQgbGlzdAogICAgbHN0KHBlYWtfZHJhd3M9cGVha19kcmF3cywgcGVha19zdW1tYXJ5PXBlYWtfc3VtbWFyeSwgCiAgICAgICAgbGV2ZWxfZHJhd3M9bGV2ZWxfZHJhd3MsIGxldmVsX3N1bW1hcnk9bGV2ZWxfc3VtbWFyeSwgCiAgICAgICAgc2xvcGVfZHJhd3M9c2xvcGVfZHJhd3MsIHNsb3BlX3N1bW1hcnk9c2xvcGVfc3VtbWFyeSkKICAKfQoKYGBgCgoKCkZ1bmN0aW9uIGZvciBjYWxjdWxhdGluZyBkaWZmZXJlbmNlIGZyb20gY291bnRlcmZhY3R1YWwKCmBgYHtyfQoKY2FsY3VsYXRlX2NvdW50ZXJmYWN0dWFsIDwtIGZ1bmN0aW9uKG1vZGVsX2RhdGEsIG1vZGVsLCBwb3B1bGF0aW9uX2Rlbm9taW5hdG9yLCBncm91cGluZ192YXI9TlVMTCwgcmVfZm9ybXVsYT1OQSl7CiAgCiAgI2VmZmVjdCB2cy4gY291bnRlcmZhY3R1YWwKICBjb3VudGVyZmFjdCA8LQogICAgICBhZGRfZXByZWRfZHJhd3Mob2JqZWN0ID0ge3ttb2RlbH19LAogICAgICAgICAgICAgICAgICAgICAgbmV3ZGF0YSA9IHt7bW9kZWxfZGF0YX19ICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3QoeWVhciwgeWVhcjIsIHlfbnVtLCB7e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSwge3tncm91cGluZ192YXJ9fSkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShhY2ZfcGVyaW9kID0gImEuIHByZS1hY2YiKSwKICAgICAgICAgICAgICAgICAgICAgIHJlX2Zvcm11bGEgPSB7e3JlX2Zvcm11bGF9fSkgJT4lCiAgICAgIGdyb3VwX2J5KC5kcmF3LCB5ZWFyLCB7e2dyb3VwaW5nX3Zhcn19LCBhY2ZfcGVyaW9kKSAlPiUKICAgICAgbXV0YXRlKC5lcHJlZF9pbmNfY291bnRlcmYgPSAuZXByZWQve3twb3B1bGF0aW9uX2Rlbm9taW5hdG9yfX0qMTAwMDAwLCAuZXByZWRfY291bnRlcmY9LmVwcmVkKSAgJT4lCiAgICAgIGZpbHRlcih5ZWFyPjE5NTcpICU+JQogICAgICB1bmdyb3VwKCkgJT4lCiAgICAgIHNlbGVjdCh5ZWFyLCB7e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSwgLmRyYXcsIC5lcHJlZF9jb3VudGVyZiwgLmVwcmVkX2luY19jb3VudGVyZiwge3tncm91cGluZ192YXJ9fSkKICAKICAjQ2FsY3VhdGUgY2FzZSBub3RpZmljYXRpb24gcmF0ZSBwZXIgZHJhdywgdGhlbiBzdW1tYXJpc2UuCiAgcG9zdF9jaGFuZ2UgPC0KICAgICAgYWRkX2VwcmVkX2RyYXdzKG9iamVjdCA9IHt7bW9kZWx9fSwKICAgICAgICAgICAgICAgICAgICAgIG5ld2RhdGEgPSB7e21vZGVsX2RhdGF9fSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KHllYXIsIHllYXIyLCB5X251bSwge3twb3B1bGF0aW9uX2Rlbm9taW5hdG9yfX0sIHt7Z3JvdXBpbmdfdmFyfX0sIGFjZl9wZXJpb2QpLAogICAgICAgICAgICAgICAgICAgICAgcmVfZm9ybXVsYSA9IHt7cmVfZm9ybXVsYX19KSAlPiUKICAgICAgZ3JvdXBfYnkoLmRyYXcsIHllYXIsIHt7Z3JvdXBpbmdfdmFyfX0sIGFjZl9wZXJpb2QpICU+JQogICAgICBtdXRhdGUoLmVwcmVkX2luYyA9IC5lcHJlZC97e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSoxMDAwMDApICAlPiUKICAgICAgZmlsdGVyKHllYXI+MTk1NykgJT4lCiAgICAgIHVuZ3JvdXAoKSAlPiUKICAgICAgc2VsZWN0KHllYXIsIHt7cG9wdWxhdGlvbl9kZW5vbWluYXRvcn19LCB7e2dyb3VwaW5nX3Zhcn19LCAuZHJhdywgLmVwcmVkLCAuZXByZWRfaW5jLCB7e2dyb3VwaW5nX3Zhcn19KSAKICAKICAjZm9yIHRoZSBvdmVyYWxsIHBlcmlvZAogICAgY291bnRlcmZhY3Rfb3ZlcmFsbCA8LQogICAgICBhZGRfZXByZWRfZHJhd3Mob2JqZWN0ID0ge3ttb2RlbH19LAogICAgICAgICAgICAgICAgICAgICAgbmV3ZGF0YSA9IHt7bW9kZWxfZGF0YX19ICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3QoeWVhciwgeWVhcjIsIHlfbnVtLCB7e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSwge3tncm91cGluZ192YXJ9fSkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShhY2ZfcGVyaW9kID0gImEuIHByZS1hY2YiKSwKICAgICAgICAgICAgICAgICAgICAgIHJlX2Zvcm11bGEgPSB7e3JlX2Zvcm11bGF9fSkgJT4lCiAgICAgIGdyb3VwX2J5KC5kcmF3LCB7e2dyb3VwaW5nX3Zhcn19KSAlPiUKICAgICAgZmlsdGVyKHllYXI+MTk1NykgJT4lCiAgICAgIHVuZ3JvdXAoKSAlPiUKICAgICAgc2VsZWN0KHt7cG9wdWxhdGlvbl9kZW5vbWluYXRvcn19LCAuZHJhdywgLmVwcmVkLCB7e2dyb3VwaW5nX3Zhcn19KSAgJT4lCiAgICAgIGdyb3VwX2J5KC5kcmF3LCB7e2dyb3VwaW5nX3Zhcn19KSAlPiUKICAgICAgc3VtbWFyaXNlKC5lcHJlZF9jb3VudGVyZiA9IHN1bSguZXByZWQpKSAKICAKICAjQ2FsY3VhdGUgY2FzZSBub3RpZmljYXRpb24gcmF0ZSBwZXIgZHJhdywgdGhlbiBzdW1tYXJpc2UuCiAgcG9zdF9jaGFuZ2Vfb3ZlcmFsbCA8LQogICAgICBhZGRfZXByZWRfZHJhd3Mob2JqZWN0ID0ge3ttb2RlbH19LAogICAgICAgICAgICAgICAgICAgICAgbmV3ZGF0YSA9IHt7bW9kZWxfZGF0YX19ICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3QoeWVhciwgeWVhcjIsIHlfbnVtLCB7e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSwge3tncm91cGluZ192YXJ9fSwgYWNmX3BlcmlvZCksCiAgICAgICAgICAgICAgICAgICAgICByZV9mb3JtdWxhID0ge3tyZV9mb3JtdWxhfX0pICU+JQogICAgICBncm91cF9ieSguZHJhdywge3tncm91cGluZ192YXJ9fSkgJT4lCiAgICAgIGZpbHRlcih5ZWFyPjE5NTcpICU+JQogICAgICB1bmdyb3VwKCkgJT4lCiAgICAgIHNlbGVjdCh7e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSwge3tncm91cGluZ192YXJ9fSwgLmRyYXcsIC5lcHJlZCkgJT4lCiAgICAgIGdyb3VwX2J5KC5kcmF3LCB7e2dyb3VwaW5nX3Zhcn19KSAlPiUKICAgICAgc3VtbWFyaXNlKC5lcHJlZCA9IHN1bSguZXByZWQpKSAKICAKICAKY291bnRlcl9wb3N0IDwtCiAgbGVmdF9qb2luKGNvdW50ZXJmYWN0LCBwb3N0X2NoYW5nZSkgJT4lCiAgICBtdXRhdGUoY2FzZXNfYXZlcnRlZCA9IC5lcHJlZF9jb3VudGVyZi0uZXByZWQsCiAgICAgICAgICAgcGN0X2NoYW5nZSA9ICguZXByZWQgLSAuZXByZWRfY291bnRlcmYpLy5lcHJlZF9jb3VudGVyZiwKICAgICAgICAgICBkaWZmX2luYzEwMGsgPSAuZXByZWRfaW5jIC0gLmVwcmVkX2luY19jb3VudGVyZiwKICAgICAgICAgICBycl9pbmMxMDBrID0gLmVwcmVkX2luYy8uZXByZWRfaW5jX2NvdW50ZXJmKSAlPiUKICAgIGdyb3VwX2J5KHllYXIsIHt7Z3JvdXBpbmdfdmFyfX0pICU+JQogICAgbWVhbl9xaShjYXNlc19hdmVydGVkLCBwY3RfY2hhbmdlLCBkaWZmX2luYzEwMGssIHJyX2luYzEwMGspICU+JQogICAgdW5ncm91cCgpCgpjb3VudGVyX3Bvc3Rfb3ZlcmFsbCA8LQogIGxlZnRfam9pbihjb3VudGVyZmFjdF9vdmVyYWxsLCBwb3N0X2NoYW5nZV9vdmVyYWxsKSAlPiUKICAgIG11dGF0ZShjYXNlc19hdmVydGVkID0gLmVwcmVkX2NvdW50ZXJmLS5lcHJlZCwKICAgICAgICAgICBwY3RfY2hhbmdlID0gKC5lcHJlZCAtIC5lcHJlZF9jb3VudGVyZikvLmVwcmVkX2NvdW50ZXJmKSAlPiUKICAgIGdyb3VwX2J5KHt7Z3JvdXBpbmdfdmFyfX0pICU+JQogICAgbWVhbl9xaShjYXNlc19hdmVydGVkLCBwY3RfY2hhbmdlKSAlPiUKICAgIHVuZ3JvdXAoKQoKbHN0KGNvdW50ZXJfcG9zdCwgY291bnRlcl9wb3N0X292ZXJhbGwpCgp9CgoKYGBgCgpGdW5jdGlvbiBmb3IgdGlkeWluZyB1cCBjb3VudGVyZmFjdHVhbHMgKG1vc3RseSBmb3IgbWFraW5nIG5pY2UgdGFibGVzKQoKYGBge3J9Cgp0aWR5X2NvdW50ZXJmYWN0dWFscyA8LSBmdW5jdGlvbihkYXRhKXsKICBkYXRhICU+JQogIG11dGF0ZShhY3Jvc3MoYyhjYXNlc19hdmVydGVkOmNhc2VzX2F2ZXJ0ZWQudXBwZXIsIGRpZmZfaW5jMTAwazpkaWZmX2luYzEwMGsudXBwZXIpLCBudW1iZXJfZm9ybWF0KGFjY3VyYWN5ID0gMC4xLCBiaWcubWFyayA9ICIsIikpKSAlPiUKICBtdXRhdGUoYWNyb3NzKGMocnJfaW5jMTAwazpycl9pbmMxMDBrLnVwcGVyKSwgbnVtYmVyX2Zvcm1hdChhY2N1cmFjeSA9IDAuMDEpKSkgJT4lCiAgbXV0YXRlKGFjcm9zcyhjKHBjdF9jaGFuZ2U6cGN0X2NoYW5nZS51cHBlciksIHBlcmNlbnQsIGFjY3VyYWN5PTAuMSkpICU+JQogIG11dGF0ZSh5ZWFyID0gYXMuY2hhcmFjdGVyKHllYXIpLAogICAgICAgICAgICBjYXNlc19hdmVydGVkID0gZ2x1ZTo6Z2x1ZSgie2Nhc2VzX2F2ZXJ0ZWR9ICh7Y2FzZXNfYXZlcnRlZC5sb3dlcn0gdG8ge2Nhc2VzX2F2ZXJ0ZWQudXBwZXJ9KSIpLAogICAgICAgICAgICBwY3RfY2hhbmdlID0gZ2x1ZTo6Z2x1ZSgie3BjdF9jaGFuZ2V9ICh7cGN0X2NoYW5nZS5sb3dlcn0gdG8ge3BjdF9jaGFuZ2UudXBwZXJ9KSIpLAogICAgICAgICAgICBkaWZmX2luYyA9IGdsdWU6OmdsdWUoIntkaWZmX2luYzEwMGt9ICh7ZGlmZl9pbmMxMDBrLmxvd2VyfSB0byB7ZGlmZl9pbmMxMDBrLnVwcGVyfSkiKSwKICAgICAgICAgICAgcnJfaW5jID0gZ2x1ZTo6Z2x1ZSgie3JyX2luYzEwMGt9ICh7cnJfaW5jMTAway5sb3dlcn0gdG8ge3JyX2luYzEwMGsudXBwZXJ9KSIpKQp9CgoKdGlkeV9jb3VudGVyZmFjdHVhbHNfb3ZlcmFsbCA8LSBmdW5jdGlvbihkYXRhKXsKICBkYXRhICU+JQogIG11dGF0ZShhY3Jvc3MoYyhjYXNlc19hdmVydGVkOmNhc2VzX2F2ZXJ0ZWQudXBwZXIpLCBudW1iZXJfZm9ybWF0KGFjY3VyYWN5ID0gMC4xLCBiaWcubWFyayA9ICIsIikpKSAlPiUKICBtdXRhdGUoYWNyb3NzKGMocGN0X2NoYW5nZTpwY3RfY2hhbmdlLnVwcGVyKSwgcGVyY2VudCwgYWNjdXJhY3k9MC4xKSkgJT4lCiAgbXV0YXRlKHllYXIgPSBhcy5jaGFyYWN0ZXIoeWVhciksCiAgICAgICAgICAgIGNhc2VzX2F2ZXJ0ZWQgPSBnbHVlOjpnbHVlKCJ7Y2FzZXNfYXZlcnRlZH0gKHtjYXNlc19hdmVydGVkLmxvd2VyfSB0byB7Y2FzZXNfYXZlcnRlZC51cHBlcn0pIiksCiAgICAgICAgICAgIHBjdF9jaGFuZ2UgPSBnbHVlOjpnbHVlKCJ7cGN0X2NoYW5nZX0gKHtwY3RfY2hhbmdlLmxvd2VyfSB0byB7cGN0X2NoYW5nZS51cHBlcn0pIikpCn0KCmBgYAoKCgojIyMgMi4gRGF0YQoKSW1wb3J0IGRhdGFzZXRzIGZvciBhbmFseXNpcwoKIyMjIyAyLjEgU2hhcGVmaWxlcwoKTWFrZSBhIG1hcCBvZiBHbGFzZ293IHdhcmRzCgpgYGB7cn0KCmdsYXNnb3dfd2FyZHNfMTk1MSA8LSBzdF9yZWFkKGhlcmUoIm1hcHBpbmcvZ2xhc2dvd193YXJkc18xOTUxLmdlb2pzb24iKSkKCmBgYAoKYGBge3J9CgojcmVhZCBpbiBTY290bGFuZCBib3VuZGFyeQpzY290bGFuZCA8LSBzdF9yZWFkKGhlcmUoIm1hcHBpbmcvU2NvdGxhbmRfYm91bmRhcnkvU2NvdGxhbmQgYm91bmRhcnkuc2hwIikpCgojbWFrZSBhIGJvdW5kaW5nIGJveCBmb3IgR2xhc2dvdwpiYm94IDwtIHN0X2Jib3goZ2xhc2dvd193YXJkc18xOTUxKSB8PiBzdF9hc19zZmMoKQoKI3Bsb3Qgc2NvdGxhbmQgd2l0aCBhIGJvdW5kaW5nIGJveCBhcm91bmQgdGhlIENpdHkgb2YgR2xhc2dvdwpzY290bGFuZF93aXRoX2Jib3ggPC0gZ2dwbG90KCkgKwogIGdlb21fc2YoZGF0YSA9IHNjb3RsYW5kLCBmaWxsPSJhbnRpcXVld2hpdGUiKSArCiAgZ2VvbV9zZihkYXRhID0gYmJveCwgY29sb3VyID0gIiNDNjBDMzAiLCBmaWxsPSJhbnRpcXVld2hpdGUiKSArCiAgdGhlbWVfdm9pZCgpICsKICB0aGVtZShwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXk3OCIsIGZpbGw9TkEsIGxpbmV3aWR0aCA9IDAuNSksCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIiNFQUY3RkEiLCBzaXplID0gMC4zKSkKCiNwbG90IHRoZSB3YXJkcwojbm90ZSB3ZSB0aWR5IHVwIHNvbWUgbmFtZXMgdG8gZml0IG9uIG1hcApnbGFzZ293X3dhcmRfbWFwIDwtIGdsYXNnb3dfd2FyZHNfMTk1MSAlPiUKICBtdXRhdGUod2FyZCA9IGNhc2Vfd2hlbih3YXJkPT0iU2hldHRsZXN0b24gYW5kIFRvbGxjcm9zcyIgfiAiU2hldHRsZXN0b24gYW5kXG5Ub2xsY3Jvc3MiLAogICAgICAgICAgICAgICAgICAgICAgICAgIHdhcmQ9PSJQYXJ0aWNrIChXZXN0KSIgfiAiUGFydGlja1xuKFdlc3QpIiwKICAgICAgICAgICAgICAgICAgICAgICAgICB3YXJkPT0iUGFydGljayAoRWFzdCkiIH4gIlBhcnRpY2tcbihFYXN0KSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgd2FyZD09Ik5vcnRoIEtlbHZpbiIgfiAiTm9ydGhcbktlbHZpbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgd2FyZD09Iktpbm5pbmcgUGFyayIgfiAiS2lubmluZ1xuUGFyayIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+IHdhcmQpKSAlPiUKICAKICBnZ3Bsb3QoKSArCiAgZ2VvbV9zZihhZXMoZmlsbD1kaXZpc2lvbikpICsKICBnZW9tX3NmX2xhYmVsKGFlcyhsYWJlbCA9IHdhcmQpLCBzaXplPTMsIGZpbGw9TkEsIGxhYmVsLnNpemUgPSBOQSwgY29sb3VyPSJibGFjayIpICsKICAjc2NhbGVfY29sb3VyX2lkZW50aXR5KCkgKwogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiU2V0MyIsIG5hbWU9IkNpdHkgb2YgR2xhc2dvdyBEaXZpc2lvbiIpICsKICB0aGVtZV9ncmV5KCkgKwogIGxhYnMoeD0iIiwKICAgICAgIHk9IiIsCiAgICAgICBmaWxsPSJEaXZpc2lvbiIpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIiwKICAgICAgICAKICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXk3OCIsIGZpbGw9TkEsIGxpbmV3aWR0aCA9IDAuNSksCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gImFudGlxdWV3aGl0ZSIsIHNpemUgPSAwLjMpLAogICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2xpbmUoY29sb3IgPSAiZ3JleTc4IikpICsKICBndWlkZXMoZmlsbD1ndWlkZV9sZWdlbmQodGl0bGUucG9zaXRpb24gPSAidG9wIiwgdGl0bGUuaGp1c3QgPSAwLjUsIHRpdGxlLnRoZW1lID0gZWxlbWVudF90ZXh0KGZhY2U9ImJvbGQiKSkpCgojYWRkIHRoZSBtYXAgb2Ygc2NvdGxhbmQgYXMgYW4gaW5zZXQKZ2xhc2dvd193YXJkX21hcCArIGluc2V0X2VsZW1lbnQoc2NvdGxhbmRfd2l0aF9iYm94LCAwLjc1LCAwLCAxLCAwLjQpCgpnZ3NhdmUoaGVyZSgiZmlndXJlcy9zMS5wbmciKSwgaGVpZ2h0PTEwLCB3aWR0aCA9IDEyKQoKCmBgYAoKQ2FsY3VsYXRlIGFyZWFzIHBlciBnZW9ncmFwaGljYWwgdW5pdAoKYGBge3J9CnNmX3VzZV9zMihGQUxTRSkgI2h0dHBzOi8vZ2l0aHViLmNvbS9yLXNwYXRpYWwvc2YvaXNzdWVzLzE3NjIKCmdsYXNnb3dfd2FyZHNfMTk1MSA8LSBnbGFzZ293X3dhcmRzXzE5NTEgJT4lCiAgbXV0YXRlKGFyZWEgPSBzdF9hcmVhKGdsYXNnb3dfd2FyZHNfMTk1MSkpCgoKZ2xhc2dvd193YXJkc18xOTUxJGFyZWFfa20gPC0gdW5pdHM6OnNldF91bml0cyhnbGFzZ293X3dhcmRzXzE5NTEkYXJlYSwga21eMikKCgpgYGAKCgpNYWtlIGRpdmlzaW9uIHNoYXBlIGZpbGVzLCBhbmQgY2FsY3VsYXRlIGFyZWEKKHN0b3BwZWQgd29ya2luZywgbmVlZCB0byBmaXghKQoKYGBge3J9CgojIGdsYXNnb3dfZGl2aXNpb25zXzE5NTEgPC0gZ2xhc2dvd193YXJkc18xOTUxICU+JQojICAgZ3JvdXBfYnkoZGl2aXNpb24pICU+JSAKIyAgIHN1bW1hcml6ZShnZW9tZXRyeSA9IHN0X3VuaW9uKGdlb21ldHJ5KSkgJT4lCiMgICBubmdlbzo6c3RfcmVtb3ZlX2hvbGVzKCkgJT4lCiMgICBtdXRhdGUoYXJlYSA9IHN0X2FyZWEoZ2xhc2dvd19kaXZpc2lvbnNfMTk1MSkpCiMgCiMgZ2xhc2dvd19kaXZpc2lvbnNfMTk1MSRhcmVhX2ttIDwtIHVuaXRzOjpzZXRfdW5pdHMoZ2xhc2dvd19kaXZpc2lvbnNfMTk1MSRhcmVhLCBrbV4yKQoKCmBgYAoKCiMjIyAzLiBEZW5vbWluYXRvcnMKCkxvYWQgaW4gdGhlIGRhdGFzZXRzIGZvciBkZW5vbm9taWF0b3JzLCBhbmQgY2hlY2sgZm9yIGNvbnNpc3RlbmN5LgoKYGBge3J9CgpvdmVyYWxsX3BvcHMgPC0gcmVhZF94bHN4KHBhdGggPSAiMjAyMy0xMS0yOF9nbGFzZ293LWFjZi54bHN4Iiwgc2hlZXQgPSAib3ZlcmFsbF9wb3B1bGF0aW9uIikKCm92ZXJhbGxfcG9wcyAlPiUKICBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpICYgISh5ZWFyKSwgIH5jb21tYSguKSkpICU+JQogIGRhdGF0YWJsZSgpCgojc2hpZnQgeWVhciB0byBtaWRwb2ludApvdmVyYWxsX3BvcHMgPC0gb3ZlcmFsbF9wb3BzICU+JQogIG11dGF0ZSh5ZWFyMiA9IHllYXIrMC41KQoKYGBgCgpOb3RlLCB3ZSBoYXZlIHRocmVlIHBvcHVsYXRpb24gZXN0aW1hdGVzOgoKMS4gUG9wdWxhdGlvbiB3aXRob3V0IGluc3RpdHV0aW9uYWxpc2VkIHBlb3BsZSBvciBwZW9wbGUgaW4gc2hpcHBpbmcKMi4gUG9wdWxhdGlvbiBpbiBpbnN0aXR1dGlvbnMKMy4gUG9wdWxhdGlvbiBpbiBzaGlwcGluZwoKKFBvcHVsYXRpb24gaW4gc2hpcHBpbmcgaXMgZXN0aW1hdGVkIGZyb20gdGhlIDE5NTEgY2Vuc3VzLCBzbyBpcyB0aGUgc2FtZSBmb3IgbW9zdCB5ZWFycykKCiMjIyMgMy4xIE92ZXJhbGwgcG9wdWxhdGlvbgoKRmlyc3QsIHBsb3QgdGhlIHRvdGFsIHBvcHVsYXRpb24KCmBgYHtyfQoKb3ZlcmFsbF9wb3BzICU+JQogIGdncGxvdCgpICsKICBnZW9tX2FyZWEoYWVzKHk9dG90YWxfcG9wdWxhdGlvbiwgeD15ZWFyMiksIGFscGhhPTAuNSwgY29sb3VyID0gIm1lZGl1bXNlYWdyZWVuIiwgZmlsbD0ibWVkaXVtc2VhZ3JlZW4iKSArCiAgZ2VvbV9wb2ludChhZXMoeT10b3RhbF9wb3B1bGF0aW9uLCB4PXllYXIyKSwgY29sb3VyID0gIm1lZGl1bXNlYWdyZWVuIikgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX3N0YXJ0KSwgbGluZXR5cGU9MykgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX2VuZCksIGxpbmV0eXBlPTMpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzPWNvbW1hKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHllYXJfbGFiZWxzLAogICAgICAgICAgICAgICAgICAgICBicmVha3MgPSB5ZWFyX2xhYmVscykgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJHbGFzZ293IENvcnBvcmF0aW9uOiB0b3RhbCBwb3B1bGF0aW9uIiwKICAgIHN1YnRpdGxlID0gIjE5NTAgdG8gMTk2MyIsCiAgICB4ID0gIlllYXIiLAogICAgeSA9ICJQb3B1bGF0aW9uIiwKICAgIGNhcHRpb24gPSAiTWlkLXllYXIgZXN0aW1hdGVzXG5NYXNzIG1pbmlhdHVyZSBYLXJheSBjYW1wYWlnbiBwZXJpb2QgYmV0d2VlbiBkYXNoZWQgbGluZXMgKDExdGggTWFyY2gtMTJ0aCBBcHJpbCAxOTU3KSIKICApICsKICB0aGVtZV9nZ2Rpc3QoKQoKCmBgYAoKTm93IHRoZSBwb3B1bGF0aW9uIGV4Y2x1ZGluZyBpbnN0aXR1dGlvbmFsaXNlZCBhbmQgc2hpcHBpbmcgcG9wdWxhdGlvbgoKYGBge3J9CgpvdmVyYWxsX3BvcHMgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fYXJlYShhZXMoeT1wb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwLCB4PXllYXIyKSwgYWxwaGE9MC41LCBjb2xvdXIgPSAicHVycGxlIiwgZmlsbD0icHVycGxlIikgKwogIGdlb21fcG9pbnQoYWVzKHk9cG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCwgeD15ZWFyMiksIGNvbG91ciA9ICJwdXJwbGUiKSArCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1hY2Zfc3RhcnQpLCBsaW5ldHlwZT0zKSArCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1hY2ZfZW5kKSwgbGluZXR5cGU9MykgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHM9Y29tbWEpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0geWVhcl9sYWJlbHMsCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHllYXJfbGFiZWxzKSArCiAgbGFicygKICAgIHRpdGxlID0gIkdsYXNnb3cgQ29ycG9yYXRpb246IHBvcHVsYXRpb24gZXhjbHVkaW5nIGluc3RpdHV0aW9uYWxpc2VkIGFuZCBzaGlwcGluZyIsCiAgICBzdWJ0aXRsZSA9ICIxOTUwIHRvIDE5NjMiLAogICAgeCA9ICJZZWFyIiwKICAgIHkgPSAiUG9wdWxhdGlvbiIsCiAgICBjYXB0aW9uID0gIk1pZC15ZWFyIGVzdGltYXRlc1xuTWFzcyBtaW5pYXR1cmUgWC1yYXkgY2FtcGFpZ24gcGVyaW9kIGJldHdlZW4gZGFzaGVkIGxpbmVzICgxMXRoIE1hcmNoLTEydGggQXByaWwgMTk1NykiCiAgKSArCiAgdGhlbWVfZ2dkaXN0KCkKCgpgYGAKCiMjIyMgMy4yIFBvcHVsYXRpb24gYnkgV2FyZAoKVGhlcmUgYXJlIDUgRGl2aXNpb25zIGNvbnRhaW5pbmcgMzcgV2FyZHMgaW4gdGhlIEdsYXNnb3cgQ29ycG9yYXRpb24sIHdpdGggY29uc2lzdGVudCBib3VuZGFyaWVzIG92ZXIgdGltZS4KCmBgYHtyfQojbG9vay11cCB0YWJsZSBmb3IgZGl2aXNpb25zIGFuZCB3YXJkcwp3YXJkX2xvb2t1cCA8LSByZWFkX3hsc3gocGF0aCA9ICIyMDIzLTExLTI4X2dsYXNnb3ctYWNmLnhsc3giLCBzaGVldCA9ICJkaXZpc2lvbnNfd2FyZHMiKQoKCndhcmRfcG9wcyA8LSByZWFkX3hsc3gocGF0aCA9ICIyMDIzLTExLTI4X2dsYXNnb3ctYWNmLnhsc3giLCBzaGVldCA9ICJ3YXJkX3BvcHVsYXRpb24iKQoKd2FyZF9wb3BzICU+JQogIG11dGF0ZShhY3Jvc3Mod2hlcmUoaXMubnVtZXJpYykgJiAhKHllYXIpLCAgfmNvbW1hKC4pKSkgJT4lCiAgZGF0YXRhYmxlKCkKCiNzaGlmdCB5ZWFyIHRvIG1pZHBvaW50CndhcmRfcG9wcyA8LSB3YXJkX3BvcHMgJT4lCiAgbXV0YXRlKHllYXIyID0geWVhciswLjUpCgojR2V0IHRoZSBEaXZpc2lvbiBwb3B1bGF0aW9uCmRpdmlzaW9uX3BvcHMgPC0gd2FyZF9wb3BzICU+JQogIGdyb3VwX2J5KGRpdmlzaW9uLCB5ZWFyKSAlPiUKICBzdW1tYXJpc2UocG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCA9IHN1bShwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICBpbnN0aXR1dGlvbnMgPSBzdW0oaW5zdGl0dXRpb25zLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICBzaGlwcGluZyA9IHN1bShzaGlwcGluZywgbmEucm0gPSBUUlVFKSwKICAgICAgICAgICAgdG90YWxfcG9wdWxhdGlvbiA9IHN1bSh0b3RhbF9wb3B1bGF0aW9uLCBuYS5ybSA9IFRSVUUpKQoKZGl2aXNpb25fcG9wcyAlPiUKICBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpICYgISh5ZWFyKSwgIH5jb21tYSguKSkpICU+JQogIGRhdGF0YWJsZSgpCgpgYGAKClBsb3QgdGhlIG92ZXJhbGwgcG9wdWxhdGlvbiBieSBEaXZpc2lvbiBhbmQgV2FyZAoKYGBge3J9CgpkaXZpc2lvbl9wb3BzICU+JQogIG11dGF0ZSh5ZWFyMiA9IHllYXIrMC41KSAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9hcmVhKGFlcyh5PXRvdGFsX3BvcHVsYXRpb24sIHg9eWVhcjIsIGNvbG91cj1kaXZpc2lvbiwgZmlsbD1kaXZpc2lvbiksIGFscGhhPTAuOCkgKwogIGdlb21fcG9pbnQoYWVzKHk9dG90YWxfcG9wdWxhdGlvbiwgeD15ZWFyMiwgY29sb3VyPWRpdmlzaW9uKSkgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX3N0YXJ0KSwgbGluZXR5cGU9MykgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX2VuZCksIGxpbmV0eXBlPTMpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzPWNvbW1hKSArCiAgZmFjZXRfd3JhcChkaXZpc2lvbn4uKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHllYXJfbGFiZWxzLAogICAgICAgICAgICAgICAgICAgICBicmVha3MgPSB5ZWFyX2xhYmVscywKICAgICAgICAgICAgICAgICAgICAgZ3VpZGUgPSBndWlkZV9heGlzKGFuZ2xlID0gOTApKSArCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTZXQzIiwgbmFtZSA9ICIiKSArCiAgc2NhbGVfY29sb3VyX2JyZXdlcihwYWxldHRlID0gIlNldDMiLCBuYW1lID0gIiIpICsKICBsYWJzKAogICAgdGl0bGUgPSAiR2xhc2dvdyBDb3Jwb3JhdGlvbjogdG90YWwgcG9wdWxhdGlvbiBieSBEaXZpc2lvbiIsCiAgICBzdWJ0aXRsZSA9ICIxOTUwIHRvIDE5NjMiLAogICAgeCA9ICJZZWFyIiwKICAgIHkgPSAiUG9wdWxhdGlvbiIsCiAgICBjYXB0aW9uID0gIk1pZC15ZWFyIGVzdGltYXRlc1xuTWFzcyBtaW5pYXR1cmUgWC1yYXkgY2FtcGFpZ24gcGVyaW9kIGJldHdlZW4gZGFzaGVkIGxpbmVzICgxMXRoIE1hcmNoLTEydGggQXByaWwgMTk1NykiCiAgKSArCiAgdGhlbWVfZ2dkaXN0KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQoKCmBgYAoKYGBge3J9Cgp3YXJkX3BvcHMgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fYXJlYShhZXMoeT10b3RhbF9wb3B1bGF0aW9uLCB4PXllYXIyLCBjb2xvdXI9ZGl2aXNpb24sIGZpbGw9ZGl2aXNpb24pLCBhbHBoYT0wLjgpICsKICBnZW9tX3BvaW50KGFlcyh5PXRvdGFsX3BvcHVsYXRpb24sIHg9eWVhcjIsIGNvbG91cj1kaXZpc2lvbikpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9zdGFydCksIGxpbmV0eXBlPTMpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9lbmQpLCBsaW5ldHlwZT0zKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscz1jb21tYSkgKwogIGZhY2V0X3dyYXAod2FyZH4uLCBuY29sPTYpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0geWVhcl9sYWJlbHMsCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHllYXJfbGFiZWxzLAogICAgICAgICAgICAgICAgICAgICBndWlkZSA9IGd1aWRlX2F4aXMoYW5nbGUgPSA5MCkpICsKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlNldDMiLCBuYW1lPSJEaXZpc2lvbiIpICsKICBzY2FsZV9jb2xvdXJfYnJld2VyKHBhbGV0dGUgPSAiU2V0MyIsIG5hbWUgPSAiRGl2aXNpb24iKSArCiAgbGFicygKICAgIHRpdGxlID0gIkdsYXNnb3cgQ2l0eTogdG90YWwgcG9wdWxhdGlvbiBieSBXYXJkIiwKICAgIHN1YnRpdGxlID0gIjE5NTAgdG8gMTk2MyIsCiAgICB4ID0gIlllYXIiLAogICAgeSA9ICJQb3B1bGF0aW9uIiwKICAgIGNhcHRpb24gPSAiTWlkLXllYXIgZXN0aW1hdGVzXG5NYXNzIG1pbmlhdHVyZSBYLXJheSBjYW1wYWlnbiBwZXJpb2QgYmV0d2VlbiBkYXNoZWQgbGluZXMgKDExdGggTWFyY2gtMTJ0aCBBcHJpbCAxOTU3KSIKICApICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpCgpnZ3NhdmUoaGVyZSgiZmlndXJlcy9zMi5wbmciKSwgaGVpZ2h0PTEwLCB3aWR0aD0xMikKCmBgYAoKQXBwcm94aW1hdGVseSwgaG93IG1hbnkgcGVyc29uLXllYXJzIG9mIGZvbGxvdy11cCBkbyB3ZSBoYXZlPwoKYGBge3J9CgpvdmVyYWxsX3BvcHMgJT4lCiAgdW5ncm91cCgpICU+JQogIHN1bW1hcmlzZShhY3Jvc3MoeWVhciwgbGVuZ3RoLCAubmFtZXMgPSAieWVhcnMiKSwKICAgICAgICAgICAgYWNyb3NzKGMocG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCwgdG90YWxfcG9wdWxhdGlvbiksIHN1bSkpICU+JQogIG11dGF0ZShhY3Jvc3Mod2hlcmUoaXMuZG91YmxlKSwgY29tbWEpKSAlPiUKICBkYXRhdGFibGUoKQoKCmBgYAoKQ2hhbmdlIGluIHBvcHVsYXRpb24gYnkgd2FyZAoKYGBge3J9Cgp3YXJkX3BvcHMgJT4lCiAgZ3JvdXBfYnkod2FyZCkgJT4lCiAgc3VtbWFyaXNlKHBjdF9jaGFuZ2VfcG9wID0gKGxhc3QocG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCkgLSBmaXJzdChwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwKSkvZmlyc3QocG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCkpICU+JQogIG11dGF0ZShwY3RfY2hhbmdlX3BvcCA9IHBlcmNlbnQocGN0X2NoYW5nZV9wb3ApKSAlPiUKICBhcnJhbmdlKHBjdF9jaGFuZ2VfcG9wKSAlPiUKICBkYXRhdGFibGUoKQogIAoKCmBgYAoKT3V0cHV0IHBvcHVsYXRpb24gZGVuc2l0eSBieSB3YXJkIGFuZCBkaXZpc29uIGZvciByZWdyZXNzaW9uIG1vZGVsbGluZwoKV2FyZHMgZmlyc3QKCihzdG9wcGVkIHdvcmtpbmcsIG5lZWQgdG8gZml4KQoKYGBge3J9CgojIHdhcmRfY292YXJpYXRlcyA8LSAgZ2xhc2dvd193YXJkc18xOTUxICU+JQojICAgbGVmdF9qb2luKHdhcmRfcG9wcykgJT4lCiMgICBtdXRhdGUocGVvcGxlX3Blcl9rbV9zcSA9IGFzLmRvdWJsZShwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwL2FyZWFfa20pKQojIAojICNwbG90IGl0IG91dAojIAojIHdhcmRfY292YXJpYXRlcyAlPiUKIyAgIGdncGxvdCgpICsKIyAgIGdlb21fc2YoYWVzKGZpbGw9cGVvcGxlX3Blcl9rbV9zcSkpICsgCiMgICBmYWNldF93cmFwKHllYXJ+LiwgbmNvbD03KSArCiMgICBzY2FsZV9maWxsX3ZpcmlkaXNfYyhvcHRpb249IkEiKSArCiMgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKIyAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0PTEpKQojIAojIGdnc2F2ZShoZXJlKCJmaWd1cmVzL3dhcmRfcG9wX2RlbnNpdHkucG5nIiksIHdpZHRoPTEwKQojIAojIHdyaXRlX3Jkcyh3YXJkX2NvdmFyaWF0ZXMsIGhlcmUoInBvcHVsYXRpb25zL3dhcmRfY292YXJpYXRlcy5yZHMiKSkKCgpgYGAKCk5vdyBkaXZpc2lvbnMgZmlyc3QKCgooc3RvcHBlZCB3b3JraW5nLCBuZWVkIHRvIGZpeCkKCmBgYHtyfQoKIyBkaXZpc2lvbl9jb3ZhcmlhdGVzIDwtICBnbGFzZ293X2RpdmlzaW9uc18xOTUxICU+JQojICAgbGVmdF9qb2luKGRpdmlzaW9uX3BvcHMpICU+JQojICAgbXV0YXRlKHBlb3BsZV9wZXJfa21fc3EgPSBhcy5kb3VibGUodG90YWxfcG9wdWxhdGlvbi9hcmVhX2ttKSkKIyAKIyAjcGxvdCBpdCBvdXQKIyAKIyBkaXZpc2lvbl9jb3ZhcmlhdGVzICU+JQojICAgZ2dwbG90KCkgKwojICAgZ2VvbV9zZihhZXMoZmlsbD1wZW9wbGVfcGVyX2ttX3NxKSkgKyAKIyAgIGdlb21fc2ZfbGFiZWwoYWVzKGxhYmVsID0gZGl2aXNpb24pLCBzaXplPTMsIGZpbGw9TkEsIGxhYmVsLnNpemUgPSBOQSwgY29sb3VyPSJibGFjayIsIGZhbWlseSA9ICJTZWdvZSBVSSIpICsKIyAgIGZhY2V0X3dyYXAoeWVhcn4uLCBuY29sPTcpICsKIyAgIHNjYWxlX2ZpbGxfdmlyaWRpc19jKG9wdGlvbj0iRyIpICsKIyAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLAojICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3Q9MSkpCiMgCiMgZ2dzYXZlKGhlcmUoImZpZ3VyZXMvZGl2aXNpb25fcG9wX2RlbnNpdHkucG5nIiksIHdpZHRoPTEwKQojIAojIHdyaXRlX3JkcyhkaXZpc2lvbl9jb3ZhcmlhdGVzLCBoZXJlKCJwb3B1bGF0aW9ucy9kaXZpc2lvbl9jb3ZhcmlhdGVzLnJkcyIpKQoKYGBgCgoKIyMjIyAzLjMgUG9wdWxhdGlvbiBieSBhZ2UgYW5kIHNleAoKYGBge3J9CgphZ2Vfc2V4IDwtIHJlYWRfeGxzeChwYXRoID0gIjIwMjMtMTEtMjhfZ2xhc2dvdy1hY2YueGxzeCIsIHNoZWV0ID0gImFnZV9zZXhfcG9wdWxhdGlvbiIpICU+JQogIHBpdm90X2xvbmdlcihjb2xzID0gYyhtYWxlLCBmZW1hbGUpLAogICAgICAgICAgICAgICBuYW1lc190byA9ICJzZXgiKQoKI2NvbGxhcHNlIGRvd24gdG8gc21hbGxlciBhZ2UgZ3JvdXBzIHRvIGJlIG1hbmFnZWFibGUKYWdlX3NleCA8LSBhZ2Vfc2V4ICU+JQogIHVuZ3JvdXAoKSAlPiUKICBtdXRhdGUoYWdlID0gY2FzZV93aGVuKGFnZSA9PSAiMCB0byA0IiB+ICIwMCB0byAwNCIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2UgPT0gIjUgdG8gOSIgfiAiMDUgdG8gMTQiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlID09ICIxMCB0byAxNCIgfiAiMDUgdG8gMTQiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlID09ICIxNSB0byAxOSIgfiAiMTUgdG8gMjQiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlID09ICIyMCB0byAyNCIgfiAiMTUgdG8gMjQiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlID09ICIyNSB0byAyOSIgfiAiMjUgdG8gMzQiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlID09ICIzMCB0byAzNCIgfiAiMjUgdG8gMzQiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlID09ICIzNSB0byAzOSIgfiAiMzUgdG8gNDQiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlID09ICI0MCB0byA0NCIgfiAiMzUgdG8gNDQiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlID09ICI0NSB0byA0OSIgfiAiNDUgdG8gNTkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlID09ICI1MCB0byA1NCIgfiAiNDUgdG8gNTkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlID09ICI1NSB0byA1OSIgfiAiNDUgdG8gNTkiLAogICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICI2MCAmIHVwIikpICU+JQogIGdyb3VwX2J5KHllYXIsIGFnZSwgc2V4KSAlPiUKICBtdXRhdGUodmFsdWUgPSBzdW0odmFsdWUpKSAlPiUKICB1bmdyb3VwKCkKCgoKbV9hZ2Vfc2V4IDwtIGxtKHZhbHVlIH4gc3BsaW5lczo6bnMoeWVhciwga25vdHMgPSAzKSphZ2Uqc2V4LCBkYXRhID0gYWdlX3NleCkKCnN1bW1hcnkobV9hZ2Vfc2V4KQoKYWdlX2xldmVscyA8LSBhZ2Vfc2V4ICU+JSBzZWxlY3QoYWdlKSAlPiUgZGlzdGluY3QoKSAlPiUgcHVsbCgpIAoKYWdlX3NleF9uZCA8LSAKICBjcm9zc2luZygKICAgIGFnZT1hZ2VfbGV2ZWxzLAogICAgc2V4PWMoIm1hbGUiLCAiZmVtYWxlIiksCiAgICB5ZWFyID0gMTk1MDoxOTYzCiAgKQoKcHJlZF9wb3BzIDwtIGFnZV9zZXhfbmQgJT4lIG1vZGVscjo6YWRkX3ByZWRpY3Rpb25zKG1fYWdlX3NleCkKCnByZWRfcG9wcyAlPiUKICBnZ3Bsb3QoYWVzKHg9eWVhciwgeT1wcmVkLCBjb2xvdXI9YWdlKSkgKwogIGdlb21fbGluZSgpICsKICBnZW9tX3BvaW50KCkgKwogIGZhY2V0X2dyaWQoc2V4fi4pICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gY29tbWEsIGxpbWl0cyA9IGMoMCwgMTI1MDAwKSkKCiNIb3cgd2VsbCBkbyB0aGV5IG1hdGNoIHVwIHdpdGggb3VyIG92ZXJhbGwgcG9wdWxhdGlvbnM/CnByZWRfcG9wcyAlPiUKICBncm91cF9ieSh5ZWFyKSAlPiUKICBzdW1tYXJpc2Uoc3VtX3ByZWRfcG9wID0gc3VtKHByZWQpKSAlPiUKICByaWdodF9qb2luKG92ZXJhbGxfcG9wcykgJT4lCiAgc2VsZWN0KHllYXIsIHN1bV9wcmVkX3BvcCwgcG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCwgdG90YWxfcG9wdWxhdGlvbikgJT4lCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBjKHN1bV9wcmVkX3BvcCwgcG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCwgdG90YWxfcG9wdWxhdGlvbikpICU+JQogIGdncGxvdChhZXMoeD15ZWFyLCB5PXZhbHVlLCBjb2xvdXI9bmFtZSkpICsKICBnZW9tX3BvaW50KCkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBjb21tYSwgbGltaXRzID0gYyg4MDAwMDAsIDEyNTAwMDApKQoKcHJlZF9wb3BzICU+JQogIGdyb3VwX2J5KHllYXIsIHNleCkgJT4lCiAgc3VtbWFyaXNlKHN1bSA9IHN1bShwcmVkKSkgJT4lCiAgZ3JvdXBfYnkoeWVhcikgJT4lCiAgbXV0YXRlKHNleF9yYXRpbyA9IGZpcnN0KHN1bSkvbGFzdChzdW0pKQpgYGAKCgpXaGF0IHBlcmNlbnRhZ2Ugb2YgYWR1bHRzICgxNSsgcGFydGljaXBhdGVkIGluIHRoZSBpbnRlcnZlbnRpb24gaW4gMTk1Nyk/CgpgYGB7cn0KCnByZWRfcG9wcyAlPiUKICB1bmdyb3VwKCkgJT4lCiAgZmlsdGVyKHllYXI9PTE5NTcpICU+JQogIGZpbHRlcihhZ2UgIT0gIjAwIHRvIDA0IiwKICAgICAgICAgYWdlICE9ICIwNSB0byAxNCIpICU+JQogIHN1bW1hcmlzZSh0b3RhbF9wb3AgPSBzdW0ocHJlZCkpICU+JQogIG11dGF0ZShjeHJfc2NyZWVuZWQgPSA2MjIzNDkpICU+JQogIG11dGF0ZShwY3RfcG9wX2N4cl9zY3JlZW5lZCA9IHBlcmNlbnQoY3hyX3NjcmVlbmVkL3RvdGFsX3BvcCkpCgpwcmVkX3BvcHMgJT4lCiAgdW5ncm91cCgpICU+JQogIGZpbHRlcih5ZWFyPT0xOTU3KSAlPiUKICBmaWx0ZXIoYWdlICE9ICIwMCB0byAwNCIsCiAgICAgICAgIGFnZSAhPSAiMDUgdG8gMTQiKSAlPiUKICBzdW1tYXJpc2UodG90YWxfcG9wID0gc3VtKHByZWQpLCAuYnk9c2V4KSAlPiUKICBtdXRhdGUoY3hyX3NjcmVlbmVkID0gYygzNDA0NzQsIDI4MTg3NSkpICU+JQogIG11dGF0ZShwY3RfcG9wX2N4cl9zY3JlZW5lZCA9IHBlcmNlbnQoY3hyX3NjcmVlbmVkL3RvdGFsX3BvcCkpCgoKYGBgCgoKUG9wdWxhdGlvbiBweXJhbWlkcwoKYGBge3J9CgpsYWJlbF9hYnMgPC0gZnVuY3Rpb24oeCkgewogIGNvbW1hKGFicyh4KSkKfQoKCnByZWRfcG9wcyAlPiUKICB1bmdyb3VwKCkgJT4lCiAgZ3JvdXBfYnkoeWVhcikgJT4lCiAgbXV0YXRlKHllYXJfcG9wID0gc3VtKHByZWQpLAogICAgICAgICBhZ2Vfc2V4X3BjdCA9IHBlcmNlbnQocHJlZC95ZWFyX3BvcCwgYWNjdXJhY3k9MC4xKSkgJT4lCiAgbXV0YXRlKHNleCA9IGNhc2Vfd2hlbihzZXg9PSJtYWxlIiB+ICJNYWxlIiwKICAgICAgICAgICAgICAgICAgICAgICAgIHNleD09ImZlbWFsZSIgfiAiRmVtYWxlIikpICU+JQogIGdncGxvdCgKICAgIGFlcyh4ID0gYWdlLCBmaWxsID0gc2V4LCAKICAgICAgICB5ID0gaWZlbHNlKHRlc3QgPSBzZXggPT0gIkZlbWFsZSIseWVzID0gLXByZWQsIG5vID0gcHJlZCkpKSArIAogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IGFnZV9zZXhfcGN0KSwKICAgICAgICAgICAgcG9zaXRpb249IHBvc2l0aW9uX3N0YWNrKHZqdXN0PTAuNSksIGNvbG91cj0id2hpdGUiLCBzaXplPTIuNSkgKwogIGZhY2V0X3dyYXAoeWVhcn4uLCBuY29sPTcpICsKICBjb29yZF9mbGlwKCkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBsYWJlbF9hYnMpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJtZWRpdW1zZWFncmVlbiIsICJwdXJwbGUiKSwgbmFtZT0iIikgKwogIHRoZW1lX2dnZGlzdCgpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZT05MCwgaGp1c3QgPSAxLCB2anVzdD0wLjUpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLAogICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleTc4IiwgZmlsbD1OQSkpICsKICBsYWJzKHg9IiIsIHk9IiIpIAoKCmdnc2F2ZShoZXJlKCJmaWd1cmVzL3MzLnBuZyIpLCB3aWR0aD0xMCkKCgpgYGAKCk5vdCBwZXJmZWN0LCBidXQgcmVzb25hYmx5IGdvb2QuIEJ1dCBhaGhoaGguLi4gdGhlIGFnZSBncm91cHMgZG9uJ3QgYWxpZ24gd2l0aCB0aGUgY2FzZSBub3RpZmljYXRpb24gYWdlIGdyb3VwcyEgQ29tZSBiYWNrIHRvIHRoaW5rIGFib3V0IHRoaXMgbGF0ZXIuCgoKIyMjIDQuIFR1YmVyY3Vsb3NpcyBjYXNlcwoKSW1wb3J0IHRoZSB0dWJlcmN1bG9zaXMgY2FzZXMgZGF0YXNldAoKCiMjIyMgNC4xIE92ZXJhbGwgbm90aWZpY2F0aW9ucwoKT3ZlcmFsbCwgYnkgeWVhci4KCmBgYHtyfQoKY2FzZXNfYnlfeWVhciA8LSByZWFkX3hsc3goIjIwMjMtMTEtMjhfZ2xhc2dvdy1hY2YueGxzeCIsIHNoZWV0ID0gImJ5X3llYXIiKQoKY2FzZXNfYnlfeWVhciU+JQogIG11dGF0ZShhY3Jvc3Mod2hlcmUoaXMubnVtZXJpYykgJiAhKHllYXIpLCAgfmNvbW1hKC4pKSkgJT4lCiAgZGF0YXRhYmxlKCkKCgojc2hpZnQgeWVhciB0byBtaWRwb2ludApjYXNlc19ieV95ZWFyIDwtIGNhc2VzX2J5X3llYXIgJT4lCiAgbXV0YXRlKHllYXIyID0geWVhciswLjUpCgpgYGAKClBsb3QgdGhlIG92ZXJhbGwgbnVtYmVyIG9mIGNhc2Ugbm90aWZpZWQgcGVyIHllYXIsIGJ5IHB1bG1vbmFyeSBhbmQgZXh0cmEgcHVsbW9uYXJ5IGNsYXNzaWZpY2F0aW9uLgoKYGBge3J9CgpjYXNlc19ieV95ZWFyICU+JQogIHNlbGVjdCgtdG90YWxfbm90aWZpY2F0aW9ucywgLXllYXIpICU+JQogIHBpdm90X2xvbmdlcihjb2xzID0gYyhwdWxtb25hcnlfbm90aWZpY2F0aW9ucywgYG5vbi1wdWxtb25hcnlfbm90aWZpY2F0aW9uc2ApKSAlPiUKICBtdXRhdGUobmFtZSA9IGNhc2Vfd2hlbihuYW1lID09ICJwdWxtb25hcnlfbm90aWZpY2F0aW9ucyIgfiAiUHVsbW9uYXJ5IFRCIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lID09ICJub24tcHVsbW9uYXJ5X25vdGlmaWNhdGlvbnMiIH4gIkV4dHJhLXB1bG1vbmFyeSBUQiIpKSAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9hcmVhKGFlcyh5PXZhbHVlLCB4PXllYXIyLCBncm91cCA9IG5hbWUsIGZpbGw9bmFtZSksIGFscGhhPTAuNSkgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX3N0YXJ0KSwgbGluZXR5cGU9MykgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX2VuZCksIGxpbmV0eXBlPTMpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzPWNvbW1hKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHllYXJfbGFiZWxzLAogICAgICAgICAgICAgICAgICAgICBicmVha3MgPSB5ZWFyX2xhYmVscykgKwogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiU2V0MSIsIG5hbWU9IiIpICsKICBsYWJzKAogICAgdGl0bGUgPSAiR2xhc2dvdyBDb3Jwb3JhdGlvbjogVHViZXJjdWxvc2lzIG5vdGlmaWNhdGlvbnMiLAogICAgc3VidGl0bGUgPSAiMTk1MCB0byAxOTYzLCBieSBUQiBkaXNlYXNlIGNsYXNzaWZpY2F0aW9uIiwKICAgIHggPSAiWWVhciIsCiAgICB5ID0gIk51bWJlciBvZiBjYXNlcyIsCiAgICBjYXB0aW9uID0gIk1hc3MgbWluaWF0dXJlIFgtcmF5IGNhbXBhaWduIHBlcmlvZCBiZXR3ZWVuIGRhc2hlZCBsaW5lcyAoMTF0aCBNYXJjaC0xMnRoIEFwcmlsIDE5NTcpIgogICkgKwogIHRoZW1lX2dnZGlzdCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikKICAKCmBgYAoKIyMjIyA0LjIgTm90aWZpY2F0aW9ucyBieSBEaXZpc2lvbgoKUmVhZCBpbiB0aGUgZGF0YXNldHMgYW5kIG1lcmdlIHRvZ2V0aGVyLgoKYGBge3J9CgojbGlzdCBhbGwgdGhlIHNoZWV0cwphbGxfc2hlZXRzIDwtIGV4Y2VsX3NoZWV0cygiMjAyMy0xMS0yOF9nbGFzZ293LWFjZi54bHN4IikKCiNnZXQgdGhlIHdhcmQgc2hlZXRzCndhcmRfc2hlZXRzIDwtIGVuZnJhbWUoYWxsX3NoZWV0cykgJT4lCiAgZmlsdGVyKGdyZXBsKCJieV93YXJkIiwgdmFsdWUpKSAlPiUKICBwdWxsKHZhbHVlKQoKCmNhc2VzX2J5X3dhcmRfc2V4X3llYXIgPC0gbWFwX2RmKHdhcmRfc2hlZXRzLCB+cmVhZF94bHN4KHBhdGggPSAiMjAyMy0xMS0yOF9nbGFzZ293LWFjZi54bHN4IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaGVldCA9IC4pKQoKY2FzZXNfYnlfd2FyZF9zZXhfeWVhciAlPiUKICBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpICYgISh5ZWFyKSwgIH5jb21tYSguKSkpICU+JQogIGRhdGF0YWJsZSgpCgpgYGAKCkFnZ3JlZ2F0ZSB0b2dldGhlciB0byBnZXQgY2FzZXMgYnkgZGl2aXNpb24KCmBgYHtyfQoKY2FzZXNfYnlfZGl2aXNpb24gPC0gY2FzZXNfYnlfd2FyZF9zZXhfeWVhciAlPiUKICBsZWZ0X2pvaW4od2FyZF9sb29rdXApICU+JQogIGdyb3VwX2J5KGRpdmlzaW9uLCB5ZWFyLCB0Yl90eXBlKSAlPiUKICBzdW1tYXJpc2UoY2FzZXMgPSBzdW0oY2FzZXMsIG5hLnJtID0gVFJVRSkpCgojc2hpZnQgeWVhciB0byBtaWRwb2ludApjYXNlc19ieV9kaXZpc2lvbiA8LSBjYXNlc19ieV9kaXZpc2lvbiAlPiUKICBtdXRhdGUoeWVhcjIgPSB5ZWFyKzAuNSkgJT4lCiAgdW5ncm91cCgpCgpjYXNlc19ieV9kaXZpc2lvbiAgJT4lCiAgc2VsZWN0KC15ZWFyMikgJT4lCiAgc2VsZWN0KHllYXIsIGV2ZXJ5dGhpbmcoKSkgJT4lCiAgbXV0YXRlKGFjcm9zcyh3aGVyZShpcy5udW1lcmljKSAmICEoeWVhciksICB+Y29tbWEoLikpKSAlPiUKICBkYXRhdGFibGUoKQoKCmNhc2VzX2J5X2RpdmlzaW9uICU+JQogIG11dGF0ZSh0Yl90eXBlID0gY2FzZV93aGVuKHRiX3R5cGUgPT0gIlB1bG1vbmFyeSIgfiAiUHVsbW9uYXJ5IFRCIiwKICAgICAgICAgICAgICAgICAgICAgICAgICB0Yl90eXBlID09ICJOb24tUHVsbW9uYXJ5IiB+ICJFeHRyYS1wdWxtb25hcnkgVEIiKSkgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fYXJlYShhZXMoeT1jYXNlcywgeD15ZWFyMiwgZ3JvdXAgPSB0Yl90eXBlLCBmaWxsPXRiX3R5cGUpLCBhbHBoYT0wLjUpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9zdGFydCksIGxpbmV0eXBlPTMpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9lbmQpLCBsaW5ldHlwZT0zKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscz1jb21tYSkgKwogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSB5ZWFyX2xhYmVscywKICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0geWVhcl9sYWJlbHMsCiAgICAgICAgICAgICAgICAgICAgIGd1aWRlID0gZ3VpZGVfYXhpcyhhbmdsZSA9IDkwKSkgKwogIGZhY2V0X3dyYXAoZGl2aXNpb25+Liwgc2NhbGVzID0gImZyZWVfeSIpICsKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlNldDEiLCBuYW1lPSIiKSArCiAgbGFicygKICAgIHRpdGxlID0gIkdsYXNnb3cgQ29ycG9yYXRpb246IFR1YmVyY3Vsb3NpcyBub3RpZmljYXRpb25zIGJ5IERpdmlzaW9uIiwKICAgIHN1YnRpdGxlID0gIjE5NTAgdG8gMTk2MywgYnkgVEIgZGlzZWFzZSBjbGFzc2lmaWNhdGlvbiIsCiAgICB4ID0gIlllYXIiLAogICAgeSA9ICJOdW1iZXIgb2YgY2FzZXMiLAogICAgY2FwdGlvbiA9ICJNYXNzIG1pbmlhdHVyZSBYLXJheSBjYW1wYWlnbiBwZXJpb2QgYmV0d2VlbiBkYXNoZWQgbGluZXMgKDExdGggTWFyY2gtMTJ0aCBBcHJpbCAxOTU3KVxuTm90ZTogZXh0cmEtcHVsbW9uYXJ5IFRCIGNhc2VzIGJ5IERpdmlzaW9uL1dhcmQgbm90IHJlcG9ydGVkIGluIDE5NjItMTk2MyIKICApICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpCgpgYGAKCiMjIyMgNC4zIE5vdGlmaWNhdGlvbnMgYnkgd2FyZAoKYGBge3J9CgoKY2FzZXNfYnlfd2FyZCA8LSBjYXNlc19ieV93YXJkX3NleF95ZWFyICU+JQogIGdyb3VwX2J5KHdhcmQsIHllYXIsIHRiX3R5cGUpICU+JQogIHN1bW1hcmlzZShjYXNlcyA9IHN1bShjYXNlcywgbmEucm0gPSBUUlVFKSkgJT4lCiAgdW5ncm91cCgpCgpjYXNlc19ieV93YXJkICU+JQogIG11dGF0ZShhY3Jvc3Mod2hlcmUoaXMubnVtZXJpYykgJiAhKHllYXIpLCAgfmNvbW1hKC4pKSkgJT4lCiAgc2VsZWN0KHllYXIsIGV2ZXJ5dGhpbmcoKSkgJT4lCiAgZGF0YXRhYmxlKCkKCiNzaGlmdCB5ZWFyIHRvIG1pZHBvaW50CmNhc2VzX2J5X3dhcmQgPC0gY2FzZXNfYnlfd2FyZCAlPiUKICBtdXRhdGUoeWVhcjIgPSB5ZWFyKzAuNSkKCmNhc2VzX2J5X3dhcmQgJT4lCiAgbXV0YXRlKHRiX3R5cGUgPSBjYXNlX3doZW4odGJfdHlwZSA9PSAiUHVsbW9uYXJ5IiB+ICJQdWxtb25hcnkgVEIiLAogICAgICAgICAgICAgICAgICAgICAgICAgIHRiX3R5cGUgPT0gIk5vbi1QdWxtb25hcnkiIH4gIkV4dHJhLXB1bG1vbmFyeSBUQiIpKSAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9hcmVhKGFlcyh5PWNhc2VzLCB4PXllYXIyLCBncm91cCA9IHRiX3R5cGUsIGZpbGw9dGJfdHlwZSksIGFscGhhPTAuOCkgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX3N0YXJ0KSwgbGluZXR5cGU9MykgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX2VuZCksIGxpbmV0eXBlPTMpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzPWNvbW1hKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHllYXJfbGFiZWxzLAogICAgICAgICAgICAgICAgICAgICBicmVha3MgPSB5ZWFyX2xhYmVscywKICAgICAgICAgICAgICAgICAgICAgZ3VpZGUgPSBndWlkZV9heGlzKGFuZ2xlID0gOTApKSArCiAgZmFjZXRfd3JhcCh3YXJkfi4sIHNjYWxlcyA9ICJmcmVlX3kiKSArCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTZXQxIiwgbmFtZT0iIikgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJHbGFzZ293IENvcnBvcmF0aW9uOiBUdWJlcmN1bG9zaXMgbm90aWZpY2F0aW9ucyBieSBXYXJkIiwKICAgIHN1YnRpdGxlID0gIjE5NTAgdG8gMTk2MywgYnkgVEIgZGlzZWFzZSBjbGFzc2lmaWNhdGlvbiIsCiAgICB4ID0gIlllYXIiLAogICAgeSA9ICJOdW1iZXIgb2YgY2FzZXMiLAogICAgY2FwdGlvbiA9ICJNYXNzIG1pbmlhdHVyZSBYLXJheSBjYW1wYWlnbiBwZXJpb2QgYmV0d2VlbiBkYXNoZWQgbGluZXMgKDExdGggTWFyY2gtMTJ0aCBBcHJpbCAxOTU3KVxuTm90ZTogZXh0cmEtcHVsbW9uYXJ5IFRCIGNhc2VzIGJ5IERpdmlzaW9uL1dhcmQgbm90IHJlcG9ydGVkIGluIDE5NjItMTk2MyIKICApICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikKCgpgYGAKCiMjIyMgNC40IE5vdGlmaWNhdGlvbnMgYnkgYWdlIGFuZCBzZXgKCkFzIHdlIGRvbid0IGhhdmUgZGVub21pbmF0b3JzLCB3ZSB3aWxsIGp1c3QgbW9kZWwgdGhlIGNoYW5nZSBpbiBjb3VudHMuCgpgYGB7cn0KCiNsaXN0IGFsbCB0aGUgc2hlZXRzCmFsbF9zaGVldHMgPC0gZXhjZWxfc2hlZXRzKCIyMDIzLTExLTI4X2dsYXNnb3ctYWNmLnhsc3giKQoKI2dldCB0aGUgd2FyZCBzaGVldHMKYWdlX3NleF9zaGVldHMgPC0gZW5mcmFtZShhbGxfc2hlZXRzKSAlPiUKICBmaWx0ZXIoZ3JlcGwoImJ5X2FnZV9zZXgiLCB2YWx1ZSkpICU+JQogIHB1bGwodmFsdWUpCgoKY2FzZXNfYnlfYWdlX3NleCA8LSBtYXBfZGYoYWdlX3NleF9zaGVldHMsIH5yZWFkX3hsc3gocGF0aCA9ICIyMDIzLTExLTI4X2dsYXNnb3ctYWNmLnhsc3giLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNoZWV0ID0gLikpCgpjYXNlc19ieV9hZ2Vfc2V4ICU+JQogIG11dGF0ZShhY3Jvc3Mod2hlcmUoaXMubnVtZXJpYykgJiAhKHllYXIpLCAgfmNvbW1hKC4pKSkgJT4lCiAgZGF0YXRhYmxlKCkKCgpgYGAKCgoKCiMjIyA1IFRCIGNhc2Ugbm90aWZpY2F0aW9uIHJhdGVzCgojIyMjIDUuMSBPdmVyYWxsIFRCIGNhc2Ugbm90aWZpY2F0aW9uIHJhdGVzCgpOb3cgY2FsY3VsYXRlIGNhc2Ugbm90aWZpY2F0aW9uIHJhdGVzIHBlciAxMDAsMDAwIHBvcHVsYXRpb24KCk1lcmdlIHRoZSBub3RpZmljYXRpb24gYW5kIHBvcHVsYXRpb24gZGVub21pbmF0b3IgZGF0YXNldHMgdG9nZXRoZXIuCgpIZXJlIHdlIG5lZWQgdG8gaW5jbHVkZSB0aGUgd2hvbGUgcG9wdWxhdGlvbiAod2l0aCBzaGlwcGluZyBhbmQgaW5zdGl0dXRpb25zKSBhcyB0aGV5IGFyZSBpbmNsdWRlZCBpbiB0aGUgbm90aWZpY2F0aW9ucy4KCmBgYHtyfQoKb3ZlcmFsbF9pbmMgPC0gb3ZlcmFsbF9wb3BzICU+JQogIGxlZnRfam9pbihjYXNlc19ieV95ZWFyKQoKb3ZlcmFsbF9pbmMgPC0gb3ZlcmFsbF9pbmMgJT4lCiAgbXV0YXRlKGluY19wdWxtXzEwMGsgPSBwdWxtb25hcnlfbm90aWZpY2F0aW9ucy90b3RhbF9wb3B1bGF0aW9uKjEwMDAwMCwKICAgICAgICAgaW5jX2VwXzEwMGsgPSBgbm9uLXB1bG1vbmFyeV9ub3RpZmljYXRpb25zYC90b3RhbF9wb3B1bGF0aW9uKjEwMDAwMCwKICAgICAgICAgaW5jXzEwMGsgPSB0b3RhbF9ub3RpZmljYXRpb25zL3RvdGFsX3BvcHVsYXRpb24qMTAwMDAwKQoKb3ZlcmFsbF9pbmMgJT4lCiAgc2VsZWN0KHllYXIsIGluY18xMDBrLCBpbmNfcHVsbV8xMDBrLCBpbmNfZXBfMTAwaykgJT4lCiAgbXV0YXRlX2F0KC52YXJzID0gdmFycyhpbmNfMTAwaywgaW5jX3B1bG1fMTAwaywgaW5jX2VwXzEwMGspLAogICAgICAgICAgICAuZnVucyA9IGZ1bnMocm91bmQpKSAlPiUKICBkYXRhdGFibGUoKQoKYGBgCgpgYGB7cn0KCm92ZXJhbGxfaW5jICU+JQogIHNlbGVjdCh5ZWFyMiwgaW5jX3B1bG1fMTAwaywgaW5jX2VwXzEwMGspICU+JQogIHBpdm90X2xvbmdlcihjb2xzID0gYyhpbmNfcHVsbV8xMDBrLCBgaW5jX2VwXzEwMGtgKSkgJT4lCiAgbXV0YXRlKG5hbWUgPSBjYXNlX3doZW4obmFtZSA9PSAiaW5jX3B1bG1fMTAwayIgfiAiUHVsbW9uYXJ5IFRCIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lID09ICJpbmNfZXBfMTAwayIgfiAiRXh0cmEtcHVsbW9uYXJ5IFRCIikpICU+JQogIGdncGxvdCgpICsKICBnZW9tX2FyZWEoYWVzKHk9dmFsdWUsIHg9eWVhcjIsIGdyb3VwID0gbmFtZSwgZmlsbD1uYW1lKSwgYWxwaGE9MC41KSArCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1hY2Zfc3RhcnQpLCBsaW5ldHlwZT0zKSArCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1hY2ZfZW5kKSwgbGluZXR5cGU9MykgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHM9Y29tbWEpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0geWVhcl9sYWJlbHMsCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHllYXJfbGFiZWxzKSArCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTZXQxIiwgbmFtZT0iIikgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJHbGFzZ293IENvcnBvcmF0aW9uOiBUdWJlcmN1bG9zaXMgY2FzZSBub3RpZmljYXRpb24gcmF0ZSIsCiAgICBzdWJ0aXRsZSA9ICIxOTUwIHRvIDE5NjMsIGJ5IFRCIGRpc2Vhc2UgY2xhc3NpZmljYXRpb24iLAogICAgeCA9ICJZZWFyIiwKICAgIHkgPSAiQ2FzZSBub3RpZmljYXRpb24gcmF0ZSAocGVyIDEwMCwwMDApIiwKICAgIGNhcHRpb24gPSAiTWFzcyBtaW5pYXR1cmUgWC1yYXkgY2FtcGFpZ24gcGVyaW9kIGJldHdlZW4gZGFzaGVkIGxpbmVzICgxMXRoIE1hcmNoLTEydGggQXByaWwgMTk1NykiCiAgKSArCiAgdGhlbWVfZ2dkaXN0KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQoKCgpgYGAKCiMjIyMgNS4yIFRCIGNhc2Ugbm90aWZpY2F0aW9uIHJhdGVzIGJ5IERpdmlzaW9uCgpgYGB7cn0KCmRpdmlzaW9uX2luYyA8LSBkaXZpc2lvbl9wb3BzICU+JQogIGxlZnRfam9pbihjYXNlc19ieV9kaXZpc2lvbikKCgpkaXZpc2lvbl9pbmMgPC0gZGl2aXNpb25faW5jICU+JQogIG11dGF0ZShpbmNfMTAwayA9IGNhc2VzL3RvdGFsX3BvcHVsYXRpb24qMTAwMDAwKQoKZGl2aXNpb25faW5jICU+JQogIHNlbGVjdCh5ZWFyLCBkaXZpc2lvbiwgdGJfdHlwZSwgaW5jXzEwMGspICU+JQogIG11dGF0ZV9hdCgudmFycyA9IHZhcnMoaW5jXzEwMGspLAogICAgICAgICAgICAuZnVucyA9IGZ1bnMocm91bmQpKSAlPiUKICBkYXRhdGFibGUoKQoKCmBgYAoKYGBge3J9CgpkaXZpc2lvbl9pbmMgJT4lCiAgbXV0YXRlKHRiX3R5cGUgPSBjYXNlX3doZW4odGJfdHlwZSA9PSAiUHVsbW9uYXJ5IiB+ICJQdWxtb25hcnkgVEIiLAogICAgICAgICAgICAgICAgICAgICAgICAgIHRiX3R5cGUgPT0gIk5vbi1QdWxtb25hcnkiIH4gIkV4dHJhLXB1bG1vbmFyeSBUQiIpKSAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9hcmVhKGFlcyh5PWluY18xMDBrLCB4PXllYXIyLCBncm91cCA9IHRiX3R5cGUsIGZpbGw9dGJfdHlwZSksIGFscGhhPTAuNSkgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX3N0YXJ0KSwgbGluZXR5cGU9MykgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX2VuZCksIGxpbmV0eXBlPTMpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzPWNvbW1hKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHllYXJfbGFiZWxzLAogICAgICAgICAgICAgICAgICAgICBicmVha3MgPSB5ZWFyX2xhYmVscywKICAgICAgICAgICAgICAgICAgICAgZ3VpZGUgPSBndWlkZV9heGlzKGFuZ2xlID0gOTApKSArCiAgZmFjZXRfd3JhcChkaXZpc2lvbn4uKSArCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTZXQxIiwgbmFtZT0iIikgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJHbGFzZ293IENvcnBvcmF0aW9uOiBUdWJlcmN1bG9zaXMgY2FzZSBub3RpZmljYXRpb24gcmF0ZSwgYnkgRGl2aXNpb24iLAogICAgc3VidGl0bGUgPSAiMTk1MCB0byAxOTYzLCBieSBUQiBkaXNlYXNlIGNsYXNzaWZpY2F0aW9uIiwKICAgIHggPSAiWWVhciIsCiAgICB5ID0gIkNhc2Ugbm90aWZpY2F0aW9uIHJhdGUgKHBlciAxMDAsMDAwKSIsCiAgICBjYXB0aW9uID0gIk1hc3MgbWluaWF0dXJlIFgtcmF5IGNhbXBhaWduIHBlcmlvZCBiZXR3ZWVuIGRhc2hlZCBsaW5lcyAoMTF0aCBNYXJjaC0xMnRoIEFwcmlsIDE5NTcpXG5Ob3RlOiBleHRyYS1wdWxtb25hcnkgVEIgY2FzZXMgYnkgRGl2aXNpb24vV2FyZCBub3QgcmVwb3J0ZWQgaW4gMTk2Mi0xOTYzIgogICkgKwogIHRoZW1lX2dnZGlzdCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikKCgoKYGBgCgojIyMjIDUuMiBUQiBjYXNlIG5vdGlmaWNhdGlvbiByYXRlcyBieSBXYXJkCgpIZXJlIHdlIHdpbGwgZmlsdGVyIG91dCB0aGUgaW5zdGl0dXRpb25zIGFuZCBoYXJib3VyIGZyb20gdGhlIGRlbm9taW5hdG9ycywgYXMgd2UgZG9uJ3QgaGF2ZSByZWxpYWJsZSBwb3B1bGF0aW9uIGRlbm9taW5hdG9ycyBmb3IgdGhlbS4KCmBgYHtyfQoKd2FyZF9pbmMgPC0gd2FyZF9wb3BzICU+JQogIGxlZnRfam9pbihjYXNlc19ieV93YXJkKQoKCndhcmRfaW5jIDwtIHdhcmRfaW5jICU+JQogIG11dGF0ZShpbmNfMTAwayA9IGNhc2VzL3BvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAqMTAwMDAwKQoKd2FyZF9pbmMgJT4lCiAgc2VsZWN0KHllYXIsIHdhcmQsIHRiX3R5cGUsIGluY18xMDBrKSAlPiUKICBtdXRhdGVfYXQoLnZhcnMgPSB2YXJzKGluY18xMDBrKSwKICAgICAgICAgICAgLmZ1bnMgPSBmdW5zKHJvdW5kKSkgJT4lCiAgZGF0YXRhYmxlKCkKCgpgYGAKCgpgYGB7cn0KCndhcmRfaW5jICU+JQogIG11dGF0ZSh0Yl90eXBlID0gY2FzZV93aGVuKHRiX3R5cGUgPT0gIlB1bG1vbmFyeSIgfiAiUHVsbW9uYXJ5IFRCIiwKICAgICAgICAgICAgICAgICAgICAgICAgICB0Yl90eXBlID09ICJOb24tUHVsbW9uYXJ5IiB+ICJFeHRyYS1wdWxtb25hcnkgVEIiKSkgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fYXJlYShhZXMoeT1pbmNfMTAwaywgeD15ZWFyMiwgZ3JvdXAgPSB0Yl90eXBlLCBmaWxsPXRiX3R5cGUpLCBhbHBoYT0wLjUpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9zdGFydCksIGxpbmV0eXBlPTMpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9lbmQpLCBsaW5ldHlwZT0zKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscz1jb21tYSkgKwogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSB5ZWFyX2xhYmVscywKICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0geWVhcl9sYWJlbHMsCiAgICAgICAgICAgICAgICAgICAgIGd1aWRlID0gZ3VpZGVfYXhpcyhhbmdsZSA9IDkwKSkgKwogIGZhY2V0X3dyYXAod2FyZH4uKSArCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTZXQxIiwgbmFtZT0iIikgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJHbGFzZ293IENvcnBvcmF0aW9uOiBUdWJlcmN1bG9zaXMgY2FzZSBub3RpZmljYXRpb24gcmF0ZSwgYnkgV2FyZCIsCiAgICBzdWJ0aXRsZSA9ICIxOTUwIHRvIDE5NjMsIGJ5IFRCIGRpc2Vhc2UgY2xhc3NpZmljYXRpb24iLAogICAgeCA9ICJZZWFyIiwKICAgIHkgPSAiSW5jaWRlbmNlIChwZXIgMTAwLDAwMCkiLAogICAgY2FwdGlvbiA9ICJNYXNzIG1pbmlhdHVyZSBYLXJheSBjYW1wYWlnbiBwZXJpb2QgYmV0d2VlbiBkYXNoZWQgbGluZXMgKDExdGggTWFyY2gtMTJ0aCBBcHJpbCAxOTU3KVxuTm90ZTogZXh0cmEtcHVsbW9uYXJ5IFRCIGNhc2VzIGJ5IERpdmlzaW9uL1dhcmQgbm90IHJlcG9ydGVkIGluIDE5NjItMTk2MyIKICApICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikKCgoKCmBgYAoKT24gYSBtYXAKCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQoKc3RfYXNfc2YobGVmdF9qb2luKHdhcmRfaW5jLCBnbGFzZ293X3dhcmRzXzE5NTEpKSAlPiUKICBmaWx0ZXIodGJfdHlwZT09IlB1bG1vbmFyeSIpICU+JQogIGdncGxvdCgpICsKICBnZW9tX3NmKGFlcyhmaWxsPWluY18xMDBrKSkgKwogIGZhY2V0X3dyYXAoeWVhcn4uLCBuY29sID0gNykgKwogIHNjYWxlX2ZpbGxfdmlyaWRpc19jKG5hbWU9IkNhc2Ugbm90aWZpY2F0aW9uIHJhdGUgKHBlciAxMDAsMDAwKSIsCiAgICAgICAgICAgICAgICAgICAgICAgb3B0aW9uID0gIkEiKSArCiAgdGhlbWVfZ2dkaXN0KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLAogICAgICAgIGxlZ2VuZC5rZXkud2lkdGggPSB1bml0KDIsICJjbSIpLAogICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleTc4IiwgZmlsbD1OQSkpICsKICBndWlkZXMoZmlsbD1ndWlkZV9jb2xvcmJhcih0aXRsZS5wb3NpdGlvbiA9ICJ0b3AiKSkKCgoKYGBgCgoKIyMjIDYuIFRCIE1vcnRhbGl0eQoKIyMjIyA2LjEgT3ZlcmFsbCBNb3J0YWxpdHkKCkltcG9ydCB0aGUgVEIgbW9ydGFsaXR5IGRhdGEuCgpGaXJzdCwgb3ZlcmFsbCBkZWF0aHMuIE5vdGUgdGhhdCBpbiB0aGUgb3JpZ2luYWwgcmVwb3J0cywgd2UgaGF2ZSBhIHB1bG1vbmFyeSBUQiBkZWF0aCByYXRlIHBlciBtaWxsaW9uIGZvciBhbGwgeWVhcnMsIGFuZCBudW1iZXJzIG9mIHB1bG1vbmFyeSBUQiBkZWF0aHMgZm9yIGVhY2ggeWVhciBhcGFydCBmcm9tIDE5NTAuCgpgYGB7cn0KCiNnZXQgdGhlIG92ZXJhbGwgbW9ydGFsaXR5IHNoZWV0cwpkZWF0aHNfc2hlZXRzIDwtIGVuZnJhbWUoYWxsX3NoZWV0cykgJT4lCiAgZmlsdGVyKGdyZXBsKCJkZWF0aHMiLCB2YWx1ZSkpICU+JQogIHB1bGwodmFsdWUpCgoKb3ZlcmFsbF9kZWF0aHMgPC0gbWFwX2RmKGRlYXRoc19zaGVldHMsIH5yZWFkX3hsc3gocGF0aCA9ICIyMDIzLTExLTI4X2dsYXNnb3ctYWNmLnhsc3giLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNoZWV0ID0gLikpCgpvdmVyYWxsX2RlYXRocyAlPiUKICBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpICYgISh5ZWFyKSwgIH5jb21tYSguKSkpICU+JQogIGRhdGF0YWJsZSgpCgoKCmBgYAoKUGxvdCB0aGUgcmF3IG51bWJlcnMgb2YgcHVsbW9uYXJ5IGRlYXRocwoKYGBge3J9CgpvdmVyYWxsX2RlYXRocyAlPiUKICBnZ3Bsb3QoYWVzKHg9eWVhciwgeT1wdWxtb25hcnlfZGVhdGhzKSkgKwogIGdlb21fbGluZShjb2xvdXIgPSAiI0RFMEQ5MiIpICsKICBnZW9tX3BvaW50KGNvbG91ciA9ICIjREUwRDkyIikgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX3N0YXJ0KSwgbGluZXR5cGU9MykgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX2VuZCksIGxpbmV0eXBlPTMpICsKICBsYWJzKHk9IlB1bG1vbmFyeSBUQiBkZWF0aHMgcGVyIHllYXIiLAogICAgICAgeCA9ICJZZWFyIiwKICAgICAgIHRpdGxlID0gIk51bWJlcnMgb2YgcHVsbW9uYXJ5IFRCIGRlYXRocyIsCiAgICAgICBzdWJ0aXRsZSA9ICJHbGFzZ293LCAxOTUwLTE5NjMiLAogICAgY2FwdGlvbiA9ICJNYXNzIG1pbmlhdHVyZSBYLXJheSBjYW1wYWlnbiBwZXJpb2QgYmV0d2VlbiBkYXNoZWQgbGluZXMgKDExdGggTWFyY2gtMTJ0aCBBcHJpbCAxOTU3KVxuTm90ZTogbm8gZGF0YSBmb3IgMTk1MCIpICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgdGhlbWUocGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5NzgiLCBmaWxsPU5BKSkKCgpgYGAKCk5vdyB0aGUgaW5jaWRlbmNlIG9mIHB1bG1vbmFyeSBUQiBkZWF0aAoKYGBge3J9Cm92ZXJhbGxfZGVhdGhzICU+JQogIGdncGxvdChhZXMoeD15ZWFyLCB5PXB1bG1vbmFyeV9kZWF0aF9yYXRlX3Blcl8xMDBrKSkgKwogIGdlb21fbGluZShjb2xvdXIgPSAiIzRENkNGQSIpICsKICBnZW9tX3BvaW50KGNvbG91ciA9ICIjNEQ2Q0ZBIikgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX3N0YXJ0KSwgbGluZXR5cGU9MykgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX2VuZCksIGxpbmV0eXBlPTMpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzPWNvbW1hKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHllYXJfbGFiZWxzLAogICAgICAgICAgICAgICAgICAgICBicmVha3MgPSB5ZWFyX2xhYmVscykgKwogIGxhYnMoeT0iQW5udWFsIGluY2lkZW5jZSBvZiBkZWF0aCAocGVyIDEwMCwwMDApIiwKICAgICAgIHggPSAiWWVhciIsCiAgICBjYXB0aW9uID0gIk1hc3MgbWluaWF0dXJlIFgtcmF5IGNhbXBhaWduIHBlcmlvZCBiZXR3ZWVuIGRhc2hlZCBsaW5lcyAoMTF0aCBNYXJjaC0xMnRoIEFwcmlsIDE5NTcpIikgKwogIHRoZW1lX2dnZGlzdCgpICsKICB0aGVtZShwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXk3OCIsIGZpbGw9TkEpKQoKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvczcucG5nIiksIHdpZHRoPTEwKQoKYGBgCgoKIyMjIDYuIFRhYmxlIDEKCk1ha2UgVGFibGUgMSBoZXJlLCBhbmQgc2F2ZSBmb3IgcHVibGljYXRpb24uCgpgYGB7cn0KCm92ZXJhbGxfcG9wcyAlPiUgCiAgc2VsZWN0KHllYXIsIHRvdGFsX3BvcHVsYXRpb24pICU+JQogIGxlZnRfam9pbihvdmVyYWxsX2luYyAlPiUKICAgICAgICAgICAgICBzZWxlY3QoeWVhciwgCiAgICAgICAgICAgICAgICAgICAgIHB1bG1vbmFyeV9ub3RpZmljYXRpb25zLCBpbmNfcHVsbV8xMDBrLAogICAgICAgICAgICAgICAgICAgICBgbm9uLXB1bG1vbmFyeV9ub3RpZmljYXRpb25zYCwgaW5jX2VwXzEwMGssCiAgICAgICAgICAgICAgICAgICAgIHRvdGFsX25vdGlmaWNhdGlvbnMsIGluY18xMDBrKSkgJT4lCiAgbGVmdF9qb2luKG92ZXJhbGxfZGVhdGhzICU+JQogICAgICAgICAgICAgIHNlbGVjdCh5ZWFyLAogICAgICAgICAgICAgICAgICAgICBwdWxtb25hcnlfZGVhdGhzLCBwdWxtb25hcnlfZGVhdGhfcmF0ZV9wZXJfMTAwaykpICU+JQogIG11dGF0ZShhY3Jvc3Mod2hlcmUoaXMubnVtZXJpYykgJiAhKHllYXIpLCAgfnJvdW5kKC4sIGRpZ2l0cz0xKSkpICU+JQogIG11dGF0ZShhY3Jvc3Mod2hlcmUoaXMubnVtZXJpYykgJiAhKHllYXIpLCAgfmNvbW1hKC4pKSkgCgpgYGAKCgpQcmVwYXJlIHRoZSBkYXRhc2V0cyBmb3IgbW9kZWxsaW5nCgpgYGB7cn0KCm1kYXRhIDwtIHdhcmRfaW5jICU+JQogIGZpbHRlcih0Yl90eXBlPT0iUHVsbW9uYXJ5IikgJT4lCiAgbXV0YXRlKGFjZl9wZXJpb2QgPSBjYXNlX3doZW4oeWVhciAlaW4lIGMoMTk1MDoxOTU2KSB+ICJhLiBwcmUtYWNmIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ZWFyICVpbiUgYygxOTU3KSB+ICJiLiBhY2YiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHllYXIgJWluJSBjKDE5NTg6MTk2MykgfiAiYy4gcG9zdC1hY2YiKSkgJT4lCiAgZ3JvdXBfYnkod2FyZCkgJT4lCiAgbXV0YXRlKHlfbnVtID0gcm93X251bWJlcigpKSAlPiUKICB1bmdyb3VwKCkKCgptZGF0YV9leHRyYXB1bG1vbmFyeSA8LSB3YXJkX2luYyAlPiUKICBmaWx0ZXIodGJfdHlwZT09Ik5vbi1QdWxtb25hcnkiKSAlPiUKICBtdXRhdGUoYWNmX3BlcmlvZCA9IGNhc2Vfd2hlbih5ZWFyICVpbiUgYygxOTUwOjE5NTYpIH4gImEuIHByZS1hY2YiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHllYXIgJWluJSBjKDE5NTcpIH4gImIuIGFjZiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeWVhciAlaW4lIGMoMTk1ODoxOTYzKSB+ICJjLiBwb3N0LWFjZiIpKSAlPiUKICBncm91cF9ieSh3YXJkKSAlPiUKICBtdXRhdGUoeV9udW0gPSByb3dfbnVtYmVyKCkpICU+JQogIHVuZ3JvdXAoKSAlPiUgCiAgZmlsdGVyKHllYXI8PTE5NjEpICNubyBkYXRhIGZvciAxOTYyIGFuZCAxOTYzCgoKI3NjYWZmb2xkIGZvciBvdmVyYWxsIHByZWRpY3Rpb25zCm92ZXJhbGxfc2NhZmZvbGQgPC0gbWRhdGEgJT4lCiAgICBzZWxlY3QoeWVhciwgeWVhcjIsIHlfbnVtLCBhY2ZfcGVyaW9kLCBwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwLCB3YXJkLCBjYXNlcykgJT4lCiAgICBncm91cF9ieSh5ZWFyLCB5ZWFyMiwgeV9udW0sIGFjZl9wZXJpb2QpICU+JQogICAgc3VtbWFyaXNlKHBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAgPSBzdW0ocG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCksCiAgICAgICAgICAgICAgY2FzZXMgPSBzdW0oY2FzZXMpKSAlPiUKICAgIHVuZ3JvdXAoKSAlPiUKICAgIG11dGF0ZShpbmNfMTAwayA9IGNhc2VzL3BvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAqMTAwMDAwKSAlPiUKICAgIGxlZnRfam9pbihtZGF0YV9leHRyYXB1bG1vbmFyeSAlPiUgZ3JvdXBfYnkoeWVhcikgJT4lCiAgICAgICAgICAgICAgICBzdW1tYXJpc2UoY2FzZXNfZXh0cmFwdWxtb25hcnkgPSBzdW0oY2FzZXMpKSkgJT4lCiAgICBtdXRhdGUoaW5jXzEwMGtfZXh0cmFwdWxtb25hcnkgPSBjYXNlc19leHRyYXB1bG1vbmFyeS9wb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwKjEwMDAwMCkKCmBgYAoKCiMjIyA3LiBQdWxtb25hcnkgVEIgbW9kZWwKCiMjIyMgNy4xIEZpdCB0aGUgbW9kZWwgYW5kIHByaW9ycwoKVGhpcyBtb2RlbHMgdGhlIGNhc2Ugbm90aWZpY2F0aW9uIHJhdGUgb3ZlciB0aW1lLCB3aXRoIGEgc3RlcCBjaGFuZ2UgZm9yIHRoZSBpbnRlcnZlbnRpb24sIGFuZCBzbG9wZSBjaGFuZ2UgYWZ0ZXIgdGhlIGludGVydmVudGlvbi4KCldvcmsgb24gdGhlIHByaW9ycyBhIGJpdC4gV2Ugd2lsbCBidWlsZCB1cCBmcm9tIGxlc3MgY29tcGxleCB0byBtb3JlIGNvbXBsZXguCgphKSBpbnRlcmNlcHQgb25seSwgdG8gcHJlZGljdCBjb3VudCBvZiBjYXNlcwoKYXQgdGhlIGludGVyY2VwdCwgd2UgZXhwZWN0IHNvbWV3aGVyZSBhcm91bmQgMjUwMC4gV2Ugd2lsbCBzZXQgdGhlIHN0YW5kYXJkIGRldmlhdGlvbiB0byBib3RoIDAuNSBhbmQgMSB0byBjaGVjayB3aGF0IGl0IGxvb2tzIGxpa2UKCmBgYHtyfQojIAojIGMocHJpb3IobG9nbm9ybWFsKDcuNjAwOTAyLCAwLjUpKSwgI2xvZygyNTAwKSA9IDcuNjAwOTAyCiMgICBwcmlvcihsb2dub3JtYWwoNy42MDA5MDIsIDEpKSkgJT4lIAojICAgcGFyc2VfZGlzdCgpICU+JSAKIyAgIAojICAgZ2dwbG90KGFlcyh5ID0gcHJpb3IsIGRpc3QgPSAuZGlzdCwgYXJncyA9IC5hcmdzKSkgKwojICAgc3RhdF9oYWxmZXllKC53aWR0aCA9IGMoLjUsIC45NSkpICsKIyAgIHNjYWxlX3lfZGlzY3JldGUoTlVMTCwgbGFiZWxzID0gc3RyX2MoImxvZ25vcm1hbChsb2coMjAwMCksICIsIGMoMC41LCAxKSwgIikiKSwKIyAgICAgICAgICAgICAgICAgICAgZXhwYW5kID0gZXhwYW5zaW9uKGFkZCA9IDAuMSkpICsKIyAgIHhsYWIoZXhwcmVzc2lvbihleHAoaXRhbGljKHApKGJldGFbMF0pKSkpICsKIyAgIGNvb3JkX2NhcnRlc2lhbih4bGltID0gYygwLDE1MDAwKSkKIyAKIyAKIyBwcmlvcihnYW1tYSgxLCAwLjAxKSkgJT4lCiMgICBwYXJzZV9kaXN0KCkgJT4lCiMgICBnZ3Bsb3QoYWVzKHk9cHJpb3IsIGRpc3QgPSAuZGlzdCwgYXJncyA9IC5hcmdzKSkgKwojICAgc3RhdF9oYWxmZXllKC53aWR0aCA9IGMoMC41LCAwLjk1KSkKIyAKIyAjbm93IGZpdCB0byBhIG1vZGVsLCBhbmQgcGxvdCBzb21lIHByaW9yIHJlYWxpc2F0aW9ucwojIAojIG1fcHJpb3IxIDwtIGJybSgKIyAgIGNhc2VzIH4gMCArIEludGVyY2VwdCwKIyAgIGZhbWlseSA9IG5lZ2Jpbm9taWFsKCksCiMgICBkYXRhID0gb3ZlcmFsbF9zY2FmZm9sZCwKIyAgIHNhbXBsZV9wcmlvciA9ICJvbmx5IiwKIyAgIHByaW9yID0gcHJpb3Iobm9ybWFsKGxvZygyMDAwKSwgMC41KSwgY2xhc3MgPSBiLCBjb2VmID0gSW50ZXJjZXB0KSArCiMgICAgICAgICAgIHByaW9yKGdhbW1hKDEsIDAuMDEpLCBjbGFzcyA9IHNoYXBlKQojICkKIyAKIyBhZGRfZXByZWRfZHJhd3Mob2JqZWN0PW1fcHJpb3IxLAojICAgICAgICAgICAgICAgICBuZXdkYXRhID0gdGliYmxlKGludGVyY2VwdD0xKSkgJT4lCiMgICBnZ3Bsb3QoYWVzKHg9aW50ZXJjZXB0LCB5PS5lcHJlZCkpICsKIyAgIHN0YXRfaGFsZmV5ZSgpICsKIyAgIHNjYWxlX3lfbG9nMTAobGFiZWxzID0gY29tbWEpCgoKYGBgCgpOb3cgdHJ5IHRvIGFkZCBpbiBhIHRlcm0gZm9yIHRoZSBlZmZlY3Qgb2YgeV9udW0uIFdlIGFudGljcGF0ZSB0aGF0IHRoZSBudW1iZXIgb2YgY2FzZXMgd2lsbCBkZWNsaW5lIGJ5IGFib3V0IDEtNSUgcGVyIHllYXIuIEhvd2V2ZXIsIGFzIHdlIGFyZSBwcmV0dHkgdW5jZXJ0YWluIGFib3V0IHRoaXMsIHdlIHdpbGwganVzdCBlbmNvZGUgYSB3ZWFrbHkgcmVndWxhcmlzaW5nIHByaW9yIHRvIHJlc3RyaWN0IHRoZSB5ZWFyIHNpemUgdG8gc2Vuc2libGUgcmFuZ2VzLgoKYGBge3J9CiMgCiMgCiMgbV9wcmlvcjIgPC0gYnJtKAojICAgY2FzZXMgfiAwICsgSW50ZXJjZXB0ICsgeV9udW0sCiMgICBmYW1pbHkgPSBuZWdiaW5vbWlhbCgpLAojICAgZGF0YSA9IG92ZXJhbGxfc2NhZmZvbGQsCiMgICBzYW1wbGVfcHJpb3IgPSAib25seSIsCiMgICBwcmlvciA9IHByaW9yKG5vcm1hbChsb2coMjAwMCksIDAuNSksIGNsYXNzID0gYiwgY29lZiA9IEludGVyY2VwdCkgKwojICAgICAgICAgICBwcmlvcihnYW1tYSgxLCAwLjAxKSwgY2xhc3MgPSBzaGFwZSkgKwojICAgICAgICAgICBwcmlvcihub3JtYWwoMCwgMC4wMSksIGNsYXNzID0gYiwgY29lZiA9IHlfbnVtKQojICkKIyAKIyBhZGRfZXByZWRfZHJhd3Mob2JqZWN0PW1fcHJpb3IyLAojICAgICAgICAgICAgICAgICBuZXdkYXRhID0gb3ZlcmFsbF9zY2FmZm9sZCkgJT4lCiMgICBnZ3Bsb3QoYWVzKHg9eWVhciwgeT0uZXByZWQpKSArCiMgICBzdGF0X2hhbGZleWUoKSArCiMgICBzY2FsZV95X2xvZzEwKGxhYmVsPWNvbW1hKQoKYGBgCgpOb3cgd2Ugd2FudCB0byBhZGQgaW4gYSBwcmlvciBmb3IgdGhlIGVmZmVjdCBvZiB0aGUgYWNmX2ludGVydmVudGlvbi4gV2UgYW50aWNpcGF0ZSB0aGUgcGVhayB0byBiZSBhbnl3aGVyZSBiZXR3ZWVuIG5vIGVmZmVjdCwgYW5kIGEgdHJpcGxpbmcKCmBgYHtyfQojIAojIG1fcHJpb3IzIDwtIGJybSgKIyAgIGNhc2VzIH4gMCArIEludGVyY2VwdCArIHlfbnVtICsgYWNmX3BlcmlvZCwKIyAgIGZhbWlseSA9IG5lZ2Jpbm9taWFsKCksCiMgICBkYXRhID0gb3ZlcmFsbF9zY2FmZm9sZCwKIyAgIHNhbXBsZV9wcmlvciA9ICJvbmx5IiwKIyAgIHByaW9yID0gcHJpb3Iobm9ybWFsKGxvZygyMDAwKSwgMC41KSwgY2xhc3MgPSBiLCBjb2VmID0gSW50ZXJjZXB0KSArCiMgICAgICAgICAgIHByaW9yKGdhbW1hKDEsIDAuMDEpLCBjbGFzcyA9IHNoYXBlKSArCiMgICAgICAgICAgIHByaW9yKG5vcm1hbCgwLCAwLjAxKSwgY2xhc3MgPSBiLCBjb2VmID0geV9udW0pICsKIyAgICAgICAgICAgcHJpb3Iobm9ybWFsKDAsIDAuMDAxKSwgY2xhc3MgPSBiKQojICkKIyAKIyAKIyBhZGRfZXByZWRfZHJhd3Mob2JqZWN0PW1fcHJpb3IzLAojICAgICAgICAgICAgICAgICBuZXdkYXRhID0gb3ZlcmFsbF9zY2FmZm9sZCkgJT4lCiMgICBnZ3Bsb3QoYWVzKHg9eWVhciwgeT0uZXByZWQpKSArCiMgICBzdGF0X2hhbGZleWUoKSArCiMgICBzY2FsZV95X2xvZzEwKGxhYmVscyA9IGNvbW1hKQojIAoKCmBgYAoKTm93IHdlIGxvb2sgYW5kIHNlZSB3aGF0IGl0IGxvb2tzIGxpa2Ugd2l0aCB0aGUgaW50ZXJhY3Rpb25zCgpgYGB7cn0KIyAKIyBtX3ByaW9yNCA8LSBicm0oCiMgICBjYXNlcyB+IDAgKyBJbnRlcmNlcHQgKyB5X251bSArIGFjZl9wZXJpb2QgKyB5X251bTphY2ZfcGVyaW9kLAojICAgZmFtaWx5ID0gbmVnYmlub21pYWwoKSwKIyAgIGRhdGEgPSBvdmVyYWxsX3NjYWZmb2xkLAojICAgc2FtcGxlX3ByaW9yID0gIm9ubHkiLAojICAgcHJpb3IgPSBwcmlvcihub3JtYWwobG9nKDI1MDApLCAxKSwgY2xhc3MgPSBiLCBjb2VmID0gSW50ZXJjZXB0KSArCiMgICAgICAgICAgIHByaW9yKGdhbW1hKDEsIDAuMDEpLCBjbGFzcyA9IHNoYXBlKSArCiMgICAgICAgICAgIHByaW9yKG5vcm1hbCgwLCAwLjAxKSwgY2xhc3MgPSBiKQojICkKIyAKIyBhZGRfZXByZWRfZHJhd3Mob2JqZWN0PW1fcHJpb3I0LAojICAgICAgICAgICAgICAgICBuZXdkYXRhID0gb3ZlcmFsbF9zY2FmZm9sZCkgJT4lCiMgICBnZ3Bsb3QoYWVzKHg9eWVhciwgeT0uZXByZWQpKSArCiMgICBzdGF0X2hhbGZleWUoKSArCiMgICBzY2FsZV95X2xvZzEwKGxhYmVsPWNvbW1hKQojIAojIAoKYGBgCgpOb3cgdHJ5IGFkZGluZyBpbiB0aGUgcmFuZG9tIGludGVyY2VwdHMKCmBgYHtyfQoKIyBjKHByaW9yKGxvZ25vcm1hbCgzLjkxMjAyMywgMC41KSksICNsb2coNTApID0gMy45MTIwMjMKIyAgIHByaW9yKGxvZ25vcm1hbCgzLjkxMjAyMywgMSkpKSAlPiUgCiMgICBwYXJzZV9kaXN0KCkgJT4lIAojICAgCiMgICBnZ3Bsb3QoYWVzKHkgPSBwcmlvciwgZGlzdCA9IC5kaXN0LCBhcmdzID0gLmFyZ3MpKSArCiMgICBzdGF0X2hhbGZleWUoLndpZHRoID0gYyguNSwgLjk1KSkgKwojICAgc2NhbGVfeV9kaXNjcmV0ZShOVUxMLCBsYWJlbHMgPSBzdHJfYygibG9nbm9ybWFsKGxvZyg1MCksICIsIGMoMC41LCAxKSwgIikiKSwKIyAgICAgICAgICAgICAgICAgICAgZXhwYW5kID0gZXhwYW5zaW9uKGFkZCA9IDAuMSkpICsKIyAgIHhsYWIoZXhwcmVzc2lvbihleHAoaXRhbGljKHApKGJldGFbMF0pKSkpICsKIyAgIGNvb3JkX2NhcnRlc2lhbih4bGltID0gYygwLDQwMCkpCiMgCiMgCiMgbV9wcmlvcjUgPC0gYnJtKAojICAgY2FzZXMgfiB5X251bSArIGFjZl9wZXJpb2QgKyB5X251bTphY2ZfcGVyaW9kICsgKCAxIHwgd2FyZCksCiMgICBmYW1pbHkgPSBuZWdiaW5vbWlhbCgpLAojICAgZGF0YSA9IG1kYXRhLAojICAgc2FtcGxlX3ByaW9yID0gIm9ubHkiLAojICAgcHJpb3IgPSBwcmlvcihub3JtYWwobG9nKDUwKSwgMSksIGNsYXNzID0gSW50ZXJjZXB0KSArCiMgICAgICAgICAgIHByaW9yKGdhbW1hKDEsIDAuMDEpLCBjbGFzcyA9IHNoYXBlKSArCiMgICAgICAgICAgIHByaW9yKG5vcm1hbCgwLCAwLjAxKSwgY2xhc3MgPSBiKSArCiMgICAgICAgICAgIHByaW9yKGV4cG9uZW50aWFsKDEpLCBjbGFzcz1zZCkKIyApCiMgCiMgCiMgYWRkX2VwcmVkX2RyYXdzKG9iamVjdD1tX3ByaW9yNSwKIyAgICAgICAgICAgICAgICAgbmV3ZGF0YSA9IG1kYXRhLAojICAgICAgICAgICAgICAgICByZV9mb3JtdWxhID0gTkEpICU+JQojICAgZ2dwbG90KGFlcyh4PXllYXIsIHk9LmVwcmVkKSkgKwojICAgc3RhdF9oYWxmZXllKCkgKwojICAgc2NhbGVfeV9sb2cxMChsYWJlbD1jb21tYSkKIyAKIyBhZGRfZXByZWRfZHJhd3Mob2JqZWN0PW1fcHJpb3I1LAojICAgICAgICAgICAgICAgICBuZXdkYXRhID0gbWRhdGEsCiMgICAgICAgICAgICAgICAgIHJlX2Zvcm11bGEgPSBOQSkgJT4lCiMgICBnZ3Bsb3QoYWVzKHg9eWVhciwgeT0uZXByZWQpKSArCiMgICBzdGF0X2hhbGZleWUoKSArCiMgICBzY2FsZV95X2xvZzEwKGxhYmVsPWNvbW1hKSArCiMgICBmYWNldF93cmFwKHdhcmR+LikKCmBgYAoKQW5kIGFkZCBpbiB0aGUgcmFuZG9tIHNsb3BlcwoKYGBge3J9CiMgCiMgbV9wcmlvcjYgPC0gYnJtKAojICAgY2FzZXMgfiAxICsgeV9udW0gKyBhY2ZfcGVyaW9kICsgeV9udW06YWNmX3BlcmlvZCArICgxICsgeV9udW0qYWNmX3BlcmlvZCB8IHdhcmQpLAojICAgZmFtaWx5ID0gbmVnYmlub21pYWwoKSwKIyAgIGRhdGEgPSBtZGF0YSwKIyAgIHNhbXBsZV9wcmlvciA9ICJvbmx5IiwKIyAgIHByaW9yID0gcHJpb3IoZ2FtbWEoMSwgMC4wMSksIGNsYXNzID0gc2hhcGUpICsKIyAgICAgICAgICAgcHJpb3Iobm9ybWFsKDAsIDAuMSksIGNsYXNzID0gYikgKwojICAgICAgICAgICBwcmlvcihleHBvbmVudGlhbCgxKSwgY2xhc3M9c2QpICsKIyAgICAgICAgICAgcHJpb3IobGtqKDIpLCBjbGFzcz1jb3IpCiMgKQojIAojIAojIAojIG1fcHJpb3I2IDwtIGJybSgKIyAgIGNhc2VzIH4gMCArIEludGVyY2VwdCArIHlfbnVtICsgYWNmX3BlcmlvZCArIHlfbnVtOmFjZl9wZXJpb2QgKyAoIHlfbnVtKmFjZl9wZXJpb2QgfCB3YXJkKSwKIyAgIGZhbWlseSA9IG5lZ2Jpbm9taWFsKCksCiMgICBkYXRhID0gbWRhdGEsCiMgICBzYW1wbGVfcHJpb3IgPSAib25seSIsCiMgICBwcmlvciA9IHByaW9yKG5vcm1hbChsb2coNTApLCAxKSwgY2xhc3MgPSBiLCBjb2VmID0gSW50ZXJjZXB0KSArCiMgICAgICAgICAgIHByaW9yKGdhbW1hKDEsIDAuMDEpLCBjbGFzcyA9IHNoYXBlKSArCiMgICAgICAgICAgIHByaW9yKG5vcm1hbCgwLCAwLjAxKSwgY2xhc3MgPSBiKSArCiMgICAgICAgICAgIHByaW9yKGV4cG9uZW50aWFsKDEwMCksIGNsYXNzPXNkKSArCiMgICAgICAgICAgIHByaW9yKGxraigyKSwgY2xhc3M9Y29yKQojICkKCgojIGFkZF9lcHJlZF9kcmF3cyhvYmplY3Q9bV9wcmlvcjYsCiMgICAgICAgICAgICAgICAgIG5ld2RhdGEgPSBtZGF0YSwKIyAgICAgICAgICAgICAgICAgcmVfZm9ybXVsYSA9IE5BKSAlPiUKIyAgIGdncGxvdChhZXMoeD15ZWFyLCB5PS5lcHJlZCkpICsKIyAgIHN0YXRfaGFsZmV5ZSgpICsKIyAgIHNjYWxlX3lfbG9nMTAobGFiZWw9Y29tbWEpCiMgCiMgYWRkX2VwcmVkX2RyYXdzKG9iamVjdD1tX3ByaW9yNiwKIyAgICAgICAgICAgICAgICAgbmV3ZGF0YSA9IG1kYXRhLAojICAgICAgICAgICAgICAgICByZV9mb3JtdWxhID0gfiggMSArIHlfbnVtICsgYWNmX3BlcmlvZCB8IHdhcmQpKSAlPiUKIyAgIGdncGxvdChhZXMoeD15ZWFyLCB5PS5lcHJlZCkpICsKIyAgIHN0YXRfaGFsZmV5ZSgpICsKIyAgIHNjYWxlX3lfbG9nMTAobGFiZWw9Y29tbWEpICsKIyAgIGZhY2V0X3dyYXAod2FyZH4uKQojIAojIHBsb3RfY291bnRlcmZhY3R1YWwobW9kZWxfZGF0YSA9IG92ZXJhbGxfc2NhZmZvbGQsIG1vZGVsPW1fcHJpb3I2LCBvdXRjb21lID0gaW5jXzEwMGssIAojICAgICAgICAgICAgICAgICAgICAgcG9wdWxhdGlvbl9kZW5vbWluYXRvciA9IHBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAsIHJlX2Zvcm11bGEgPSBOQSkKIyAKIyBwbG90X2NvdW50ZXJmYWN0dWFsKG1vZGVsX2RhdGEgPSBtZGF0YSwgbW9kZWw9bV9wcmlvcjYsIG91dGNvbWUgPSBpbmNfMTAwaywgCiMgICAgICAgICAgICAgICAgICAgICBwb3B1bGF0aW9uX2Rlbm9taW5hdG9yID0gcG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCwgZ3JvdXBpbmdfdmFyID0gd2FyZCwgd2FyZCwKIyAgICAgICAgICAgICAgICAgICAgIHJlX2Zvcm11bGEgPSB+KCAxICsgeV9udW0gKyBhY2ZfcGVyaW9kIHwgd2FyZCkpCgpgYGAKCgpJc3N1ZSBoZXJlIGlzIHRoZSBub24tY2VudHJlZCBwYXJhbWV0ZXJpc2F0aW9uIG9mIHRoZSBpbnRlcmNlcHQgcHJpb3IuLi4gRmVlbCBsaWtlIHRoaXMgaXMgYSBtb3JlIGludGVycHJldGFibGUgd2F5IHRvIHNldCBwcmlvcnMuLi4gYnV0IHdpbGwgcmV2ZXJ0IHRvIGNlbnRyZWQgcGFyYW1ldGVyaXNhdGlvbiBmb3IgdGhlIG1lYW50aW1lLgoKCmBgYHtyfQojIG1fY2VudGVyZWRfcHJpb3IgPC0gYnJtKAojICAgY2FzZXMgfiAxICsgeV9udW0qYWNmX3BlcmlvZCArICgxICsgeV9udW0qYWNmX3BlcmlvZCB8IHdhcmQpICsgb2Zmc2V0KGxvZyhwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwKSksCiMgICAgICAgICAgICAgICAgICAgZGF0YSA9IG1kYXRhLAojICAgICAgICAgICAgICAgICAgIGZhbWlseSA9IG5lZ2Jpbm9taWFsKCksCiMgICAgICAgICAgICAgICAgICAgc2VlZCA9IDEyMzQsCiMgICAgICAgICAgICAgICAgICAgY2hhaW5zID0gNCwgY29yZXMgPSA0LAojICAgICAgICAgICAgICAgICAgIHByaW9yID0gcHJpb3Iobm9ybWFsKDAsMTAwMCksIGNsYXNzID0gSW50ZXJjZXB0KSArCiMgICAgICAgICAgICAgICAgICAgICAgICAgICBwcmlvcihnYW1tYSgwLjAxLCAwLjAxKSwgY2xhc3MgPSBzaGFwZSkgKwojICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJpb3Iobm9ybWFsKDAsIDEpLCBjbGFzcyA9IGIpICsKIyAgICAgICAgICAgICAgICAgICAgICAgICAgIHByaW9yKGV4cG9uZW50aWFsKDEpLCBjbGFzcz1zZCkgKwojICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJpb3IobGtqKDIpLCBjbGFzcz1jb3IpLAojICAgICAgICAgICAgICAgICAgIHNhbXBsZV9wcmlvciA9ICJvbmx5IikKIyAKIyBwbG90KG1fY2VudGVyZWRfcHJpb3IpCiMgCiMgcGxvdF9jb3VudGVyZmFjdHVhbChtb2RlbF9kYXRhID0gb3ZlcmFsbF9zY2FmZm9sZCwgbW9kZWw9bV9jZW50ZXJlZF9wcmlvciwgb3V0Y29tZSA9IGluY18xMDBrLCAKIyAgICAgICAgICAgICAgICAgICAgIHBvcHVsYXRpb25fZGVub21pbmF0b3IgPSBwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwLCByZV9mb3JtdWxhID0gTkEpCiMgCiMgcGxvdF9jb3VudGVyZmFjdHVhbChtb2RlbF9kYXRhID0gbWRhdGEsIG1vZGVsPW1fY2VudGVyZWRfcHJpb3IsIG91dGNvbWUgPSBpbmNfMTAwaywgCiMgICAgICAgICAgICAgICAgICAgICBwb3B1bGF0aW9uX2Rlbm9taW5hdG9yID0gcG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCwgZ3JvdXBpbmdfdmFyID0gd2FyZCwgd2FyZCwKIyAgICAgICAgICAgICAgICAgICAgIHJlX2Zvcm11bGEgPSB+KCAxICsgeV9udW0qYWNmX3BlcmlvZCB8IHdhcmQpKQoKYGBgCgoKCgpMb29rIGF0IHRoZSBtZWFuIGFuZCB2YXJpYW5jZSBvZiBjb3VudHMgKGNvdW50cyBvZiBwdWxtb25hcnkgbm90aWZpY2F0aW9ucyBhcmUgd2hhdCB3ZSBhcmUgcHJlZGljdGluZykKCmBgYHtyfQoKI01lYW4gb2YgY291bnRzIHBlciB5ZWFyCm1lYW4obWRhdGEkY2FzZXMpCiN2YXJpYW5jZSBvZiBjb3VudHMgcGVyIHllYXIKdmFyKG1kYXRhJGNhc2VzKQoKYGBgCgoKCgoKUXVpdGUgYSBiaXQgb2Ygb3Zlci1kaXNwZXJzaW9uIGhlcmUsIHNvIG5lZ2F0aXZlIGJpbm9taWFsIGRpc3RyaWJ1dGlvbiBtaWdodCBiZSBhIGJldHRlciBjaG9pY2Ugb2YgZGlzdHJpYnV0aW9uYWwgZmFtaWx5IHRoYW4gUG9pc3Nvbi4KCkZpdCB0aGUgbW9kZWwgd2l0aCB0aGUgZGF0YQoKYGBge3J9CgptX3B1bG1vbmFyeSA8LSBicm0oCiAgY2FzZXMgfiAxICsgeV9udW0qYWNmX3BlcmlvZCArICgxICsgeV9udW0qYWNmX3BlcmlvZCB8IHdhcmQpICsgb2Zmc2V0KGxvZyhwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwKSksCiAgICAgICAgICAgICAgICAgIGRhdGEgPSBtZGF0YSwKICAgICAgICAgICAgICAgICAgZmFtaWx5ID0gbmVnYmlub21pYWwoKSwKICAgICAgICAgICAgICAgICAgc2VlZCA9IDEyMzQsCiAgICAgICAgICAgICAgICAgIGNoYWlucyA9IDQsIGNvcmVzID0gNCwKICAgICAgICAgICAgICAgICAgcHJpb3IgPSBwcmlvcihub3JtYWwoMCwxKSwgY2xhc3MgPSBJbnRlcmNlcHQpICsKICAgICAgICAgICAgICAgICAgICAgICAgICBwcmlvcihnYW1tYSgwLjAxLCAwLjAxKSwgY2xhc3MgPSBzaGFwZSkgKwogICAgICAgICAgICAgICAgICAgICAgICAgIHByaW9yKG5vcm1hbCgwLCAxKSwgY2xhc3MgPSBiKSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgcHJpb3IoZXhwb25lbnRpYWwoMSksIGNsYXNzPXNkKSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgcHJpb3IobGtqKDQpLCBjbGFzcz1jb3IpLAogIGNvbnRyb2wgPSBsaXN0KGFkYXB0X2RlbHRhID0gMC45KSkKICAKI2NoZWNrIG1vZGVsIGRpYWdub3N0aWNzCnN1bW1hcnkobV9wdWxtb25hcnkpCnBsb3QobV9wdWxtb25hcnkpCgpwcF9jaGVjayhtX3B1bG1vbmFyeSwgdHlwZT0nZWNkZl9vdmVybGF5JykKcHJpb3Jfc3VtbWFyeShtX3B1bG1vbmFyeSkKCmBgYAoKCiMjIyMgNy4yIFN1bW1hcmlzZSBjaGFuZ2UgaW4gQ05ScwoKU3VtbWFyaXNlIHRoZSBwb3N0ZXJpb3IgaW4gZ3JhcGhpY2FsIGZvcm0KCmBgYHtyfQoKZjFiIDwtIHBsb3RfY291bnRlcmZhY3R1YWwobW9kZWxfZGF0YSA9IG92ZXJhbGxfc2NhZmZvbGQsIG1vZGVsID0gbV9wdWxtb25hcnksIAogICAgICAgICAgICAgICAgICAgICAgICAgICBwb3B1bGF0aW9uX2Rlbm9taW5hdG9yID0gcG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCwgb3V0Y29tZSA9IGluY18xMDBrLCBncm91cGluZ192YXI9TlVMTCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVfZm9ybXVsYSA9IE5BKQogIApmMWIKYGBgCgpNYWtlIHRoaXMgaW50byBhIGZpZ3VyZSBjb21iaW5lZCB3aXRoIHRoZSBtYXAgb2YgZW1waXJpY2FsIGRhdGEKCmBgYHtyfQoKZjFhIDwtIHN0X2FzX3NmKGxlZnRfam9pbih3YXJkX2luYywgZ2xhc2dvd193YXJkc18xOTUxKSkgJT4lCiAgZmlsdGVyKHRiX3R5cGU9PSJQdWxtb25hcnkiKSAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9zZihhZXMoZmlsbD1pbmNfMTAwaykpICsKICBmYWNldF93cmFwKHllYXJ+LiwgbmNvbCA9IDcpICsKICBzY2FsZV9maWxsX3ZpcmlkaXNfYyhuYW1lPSJDYXNlIG5vdGlmaWNhdGlvbiByYXRlIChwZXIgMTAwLDAwMCkiLAogICAgICAgICAgICAgICAgICAgICAgIG9wdGlvbiA9ICJBIikgKwogIHRoZW1lX2dnZGlzdCgpICsKICB0aGVtZShwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXk3OCIsIGZpbGw9TkEpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLAogICAgICAgIGxlZ2VuZC5rZXkud2lkdGggPSB1bml0KDIsICJjbSIpLAogICAgICAgIGxlZ2VuZC50aXRsZS5hbGlnbiA9IDAuNSwKICAgICAgICB0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9OCksCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGU9NDUsIHNpemU9NiwgaGp1c3Q9MSksCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZT02KSkgKwogIGd1aWRlcyhmaWxsPWd1aWRlX2NvbG9yYmFyKHRpdGxlLnBvc2l0aW9uID0gInRvcCIpKQoKKGYxYSAvIGYxYikgKyBwbG90X2Fubm90YXRpb24odGFnX2xldmVscyA9ICJBIikKCmdnc2F2ZShoZXJlKCJmaWd1cmVzL2YxLnBuZyIpKQoKYGBgCgpTdW1tYXJ5IG9mIGNoYW5nZSBpbiBub3RpZmljYXRpb25zIG51bWVyaWNhbGx5CgpgYGB7cn0KCm92ZXJhbGxfY2hhbmdlIDwtIHN1bW1hcmlzZV9jaGFuZ2UobW9kZWxfZGF0YT1vdmVyYWxsX3NjYWZmb2xkLCBtb2RlbD1tX3B1bG1vbmFyeSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcG9wdWxhdGlvbl9kZW5vbWluYXRvcj1wb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwLCBncm91cGluZ192YXI9TlVMTCwgcmVfZm9ybXVsYSA9IE5BKQoKI3dhbnQgdG8ga2VlcCB0aGUgc3VtbWFyeSBlc3RpbWF0ZXMgaGVyZQp0b2tlZXAgPC0gYygicGVha19zdW1tYXJ5IiwgImxldmVsX3N1bW1hcnkiLCAic2xvcGVfc3VtbWFyeSIpCgojc3VtbWFyeSBtZWFzdXJlcyBpbiBhIHRhYmxlCm92ZXJhbGxfY2hhbmdlICU+JQogIGtlZXAoKG5hbWVzKC4pICVpbiUgdG9rZWVwKSkgJT4lCiAgYmluZF9yb3dzKCkgJT4lCiAgbXV0YXRlKGFjcm9zcyhjKGVzdGltYXRlOi51cHBlciksIG51bWJlciwgYWNjdXJhY3k9MC4wMSkpICU+JQogIHNlbGVjdChtZWFzdXJlLCBldmVyeXRoaW5nKCkpICU+JQogIGRhdGF0YWJsZSgpCgogIApgYGAKCgojIyMjIDcuMyBDb21wYXJlZCB0byBjb3VudGVyZmFjdHVhbAoKTnVtYmVycyBvZiBwdWxtb25hcnkgVEIgY2FzZXMgYXZlcnRlZCBjb21wYXJlZCB0byBjb3VudGVyZmFjdHVhbCBwZXIgeWVhci4KCmBgYHtyfQoKb3ZlcmFsbF9wdWxtb25hcnlfY291bnRlcmYgPC0gY2FsY3VsYXRlX2NvdW50ZXJmYWN0dWFsKG1vZGVsX2RhdGEgPSBvdmVyYWxsX3NjYWZmb2xkLCBtb2RlbD1tX3B1bG1vbmFyeSwgcG9wdWxhdGlvbl9kZW5vbWluYXRvciA9IHBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXApCgpvdmVyYWxsX3B1bG1vbmFyeV9jb3VudGVyZiRjb3VudGVyX3Bvc3QgJT4lCiAgbXV0YXRlKGFjcm9zcyhjKGNhc2VzX2F2ZXJ0ZWQ6Y2FzZXNfYXZlcnRlZC51cHBlciwgZGlmZl9pbmMxMDBrOmRpZmZfaW5jMTAway51cHBlciksIG51bWJlcl9mb3JtYXQoYWNjdXJhY3kgPSAwLjEsIGJpZy5tYXJrID0gIiwiKSkpICU+JQogIG11dGF0ZShhY3Jvc3MoYyhycl9pbmMxMDBrOnJyX2luYzEwMGsudXBwZXIpLCBudW1iZXJfZm9ybWF0KGFjY3VyYWN5ID0gMC4wMSkpKSAlPiUKICBtdXRhdGUoYWNyb3NzKGMocGN0X2NoYW5nZTpwY3RfY2hhbmdlLnVwcGVyKSwgcGVyY2VudCwgYWNjdXJhY3k9MC4xKSkgJT4lCiAgZGF0YXRhYmxlKCkKCgpgYGAKClRvdGFsIHB1bG1vbmFyeSBUQiBjYXNlcyBhdmVydGVkIGJldHdlZW4gMTk1OCBhbmQgMTk2MwoKYGBge3J9CgpvdmVyYWxsX3B1bG1vbmFyeV9jb3VudGVyZiRjb3VudGVyX3Bvc3Rfb3ZlcmFsbCAlPiUKICBtdXRhdGUoYWNyb3NzKGMoY2FzZXNfYXZlcnRlZDpjYXNlc19hdmVydGVkLnVwcGVyKSwgbnVtYmVyX2Zvcm1hdChhY2N1cmFjeSA9IDAuMSwgYmlnLm1hcmsgPSAiLCIpKSkgJT4lCiAgbXV0YXRlKGFjcm9zcyhjKHBjdF9jaGFuZ2U6cGN0X2NoYW5nZS51cHBlciksIHBlcmNlbnQsIGFjY3VyYWN5PTAuMSkpICU+JQogIGRhdGF0YWJsZSgpCgoKYGBgCgojIyMjIDcuNCBDb3JyZWxhdGlvbiBiZXR3ZWVuIFJSLnBlYWssIFJSLmxldmVsLCBhbmQgUlIuc2xvcGUKCldoYXQgYXJlIHRoZSBjb3JyZWxhdGlvbnMgYmV0d2VlbiBwZWFrLCBsZXZlbCwgYW5kIHNsb3BlPwoKYGBge3J9CgojUlIucGVhayBoaXN0b2dyYW0KYSA8LSBvdmVyYWxsX2NoYW5nZSRwZWFrX2RyYXdzICU+JQogIGdncGxvdCgpICsKICBnZW9tX2hpc3RvZ3JhbShhZXMoeD1lc3RpbWF0ZSksIGZpbGw9ImRhcmtibHVlIiwgY29sb3VyPSJkYXJrYmx1ZSIsIGFscGhhPTAuMykrCiAgc2NhbGVfZmlsbF9ncmFkaWVudChoaWdoPSJsaWdodGJsdWUxIixsb3c9ImRhcmtibHVlIikgKwogIHRoZW1lX2dnZGlzdCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5NzgiLCBmaWxsPU5BKSkgKwogIGxhYnMoeD0iUlIucGVhayIsCiAgICAgICB5PSIiKQoKI1JSLiBsZXZlbCBoaXN0b2dyYW0KYiA8LSBvdmVyYWxsX2NoYW5nZSRsZXZlbF9kcmF3cyAgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21faGlzdG9ncmFtKGFlcyh4PWVzdGltYXRlKSwgZmlsbD0iZGFya2JsdWUiLCBjb2xvdXI9ImRhcmtibHVlIiwgYWxwaGE9MC4zKSsKICBzY2FsZV9maWxsX2dyYWRpZW50KGhpZ2g9ImxpZ2h0Ymx1ZTEiLGxvdz0iZGFya2JsdWUiKSArCiAgdGhlbWVfZ2dkaXN0KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXk3OCIsIGZpbGw9TkEpKSArCiAgbGFicyh4PSJSUi5sZXZlbCIsCiAgICAgICB5PSIiKQoKI1JSLnNsb3BlIGhpc3RvZ3JhbQpjIDwtIG92ZXJhbGxfY2hhbmdlJHNsb3BlX2RyYXdzICU+JQogIGdncGxvdCgpICsKICBnZW9tX2hpc3RvZ3JhbShhZXMoeD1lc3RpbWF0ZSksIGZpbGw9ImRhcmtibHVlIiwgY29sb3VyPSJkYXJrYmx1ZSIsIGFscGhhPTAuMykrCiAgc2NhbGVfZmlsbF9ncmFkaWVudChoaWdoPSJsaWdodGJsdWUxIixsb3c9ImRhcmtibHVlIikgKyAgCiAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwgNikpICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleTc4IiwgZmlsbD1OQSkpICsKICBsYWJzKHg9IlJSLnNsb3BlIiwKICAgICAgIHk9IiIpCgoKI0NvcnJlbGF0aW9uIGJldHdlZW4gUlIucGVhayBhbmQgUlIubGV2ZWwKY29yX3JyX3BlYWtfcnJfbGV2ZWwgPC0gcm91bmQoY29yKHBsdWNrKG92ZXJhbGxfY2hhbmdlJHBlYWtfZHJhd3MkZXN0aW1hdGUpLCBwbHVjayhvdmVyYWxsX2NoYW5nZSRsZXZlbF9kcmF3cyRlc3RpbWF0ZSkpLCBkaWdpdHMgPSAyKQoKI0NvcnJlbGF0aW9uIGJldHdlZW4gUlIucGVhayBhbmQgUlIuc2xvcGUKY29yX3JyX3BlYWtfcnJfc2xvcGUgPC0gcm91bmQoY29yKHBsdWNrKG92ZXJhbGxfY2hhbmdlJHBlYWtfZHJhd3MkZXN0aW1hdGUpLCBwbHVjayhvdmVyYWxsX2NoYW5nZSRzbG9wZV9kcmF3cyRlc3RpbWF0ZSkpLCBkaWdpdHMgPSAyKQoKI0NvcnJlbGF0aW9uIGJldHdlZW4gUlIubGV2ZWwgYW5kIFJSLnNsb3BlCmNvcl9ycl9sZXZlbF9ycl9zbG9wZSA8LSByb3VuZChjb3IocGx1Y2sob3ZlcmFsbF9jaGFuZ2UkbGV2ZWxfZHJhd3MkZXN0aW1hdGUpLCBwbHVjayhvdmVyYWxsX2NoYW5nZSRzbG9wZV9kcmF3cyRlc3RpbWF0ZSkpLCBkaWdpdHMgPSAyKQoKCiNwbG90IG9mIGNvcnJlbGF0aW9uIGJldHdlZW4gUlIucGVhayBhbmQgUlIubGV2ZWwKZCA8LSBiaW5kX2NvbHMoUlIucGVhaz1wbHVjayhvdmVyYWxsX2NoYW5nZSRwZWFrX2RyYXdzJGVzdGltYXRlKSwgCiAgICAgICAgICBSUi5sZXZlbCA9cGx1Y2sob3ZlcmFsbF9jaGFuZ2UkbGV2ZWxfZHJhd3MkZXN0aW1hdGUpKSAlPiUKICBnZ3Bsb3QoYWVzKHk9UlIucGVhaywgeCA9IFJSLmxldmVsKSkgKwogIGdlb21faGV4KCkgKwogIGdlb21fc21vb3RoKHNlPUZBTFNFLCBjb2xvdXI9ImZpcmVicmljayIsIG1ldGhvZCA9ICJsbSIpICsKICBnZW9tX3RleHQoYWVzKHk9Mi4yLCB4PTAuNTgsIGxhYmVsPWNvcl9ycl9wZWFrX3JyX2xldmVsKSwgY29sb3VyPSJmaXJlYnJpY2siKSAgKwogIHNjYWxlX2ZpbGxfZ3JhZGllbnQoaGlnaD0ibGlnaHRibHVlMSIsbG93PSJkYXJrYmx1ZSIpICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleTc4IiwgZmlsbD1OQSkpCgojcGxvdCBvZiBjb3JyZWxhdGlvbiBiZXR3ZWVuIFJSLnBlYWsgYW5kIFJSLnNsb3BlCmUgPC0gYmluZF9jb2xzKFJSLnBlYWs9cGx1Y2sob3ZlcmFsbF9jaGFuZ2UkcGVha19kcmF3cyRlc3RpbWF0ZSksIAogICAgICAgICAgUlIuc2xvcGUgPXBsdWNrKG92ZXJhbGxfY2hhbmdlJHNsb3BlX2RyYXdzJGVzdGltYXRlKSkgJT4lCiAgZ2dwbG90KGFlcyh5PVJSLnBlYWssIHggPSBSUi5zbG9wZSkpICsKICBnZW9tX2hleCgpICsKICBnZW9tX3Ntb290aChzZT1GQUxTRSwgY29sb3VyPSJmaXJlYnJpY2siLCBtZXRob2QgPSAibG0iKSArCiAgZ2VvbV90ZXh0KGFlcyh5PTIuMSwgeD0wLjUsIGxhYmVsPWNvcl9ycl9wZWFrX3JyX3Nsb3BlKSwgY29sb3VyPSJmaXJlYnJpY2siKSAgKwogIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKDAsIDYpKSArCiAgc2NhbGVfZmlsbF9ncmFkaWVudChoaWdoPSJsaWdodGJsdWUxIixsb3c9ImRhcmtibHVlIikgKwogIHRoZW1lX2dnZGlzdCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5NzgiLCBmaWxsPU5BKSkKCiNwbG90IG9mIGNvcnJlbGF0aW9uIGJldHdlZW4gUlIubGV2ZWwgYW5kIFJSLnNsb3BlCmYgPC0gYmluZF9jb2xzKFJSLmxldmVsPXBsdWNrKG92ZXJhbGxfY2hhbmdlJGxldmVsX2RyYXdzJGVzdGltYXRlKSwgCiAgICAgICAgICBSUi5zbG9wZSA9cGx1Y2sob3ZlcmFsbF9jaGFuZ2Ukc2xvcGVfZHJhd3MkZXN0aW1hdGUpKSAlPiUKICBnZ3Bsb3QoYWVzKHk9UlIubGV2ZWwsIHggPSBSUi5zbG9wZSkpICsKICBnZW9tX2hleCgpICsKICBnZW9tX3Ntb290aChzZT1GQUxTRSwgY29sb3VyPSJmaXJlYnJpY2siLCBtZXRob2QgPSAibG0iKSArCiAgZ2VvbV90ZXh0KGFlcyh5PTAuNzUsIHg9MC41LCBsYWJlbD1jb3JfcnJfbGV2ZWxfcnJfc2xvcGUpLCBjb2xvdXI9ImZpcmVicmljayIpICArICAKICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygwLCA2KSkgKwogIHNjYWxlX2ZpbGxfZ3JhZGllbnQoaGlnaD0ibGlnaHRibHVlMSIsbG93PSJkYXJrYmx1ZSIpICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleTc4IiwgZmlsbD1OQSkpCgoKKHBsb3Rfc3BhY2VyKCkgKyBwbG90X3NwYWNlcigpICsgYykgLwogIChwbG90X3NwYWNlcigpICsgYiArIGYpIC8KICAoYSArIGQgKyBlKQoKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvcHVsbW9uYXJ5X2NvcnMucGRmIiksIHdpZHRoPTgsIGhlaWdodD04KQoKCgpgYGAKCgojIyMjIDcuNSBXYXJkIGxldmVsIHB1bG1vbmFyeSBUQiBlc3RpbWF0ZXMKClBsb3QgdGhlIGNvdW50ZXJmYWN0dWFsIGF0IHdhcmQgbGV2ZWwKCmBgYHtyfQoKcGxvdF9jb3VudGVyZmFjdHVhbChtb2RlbF9kYXRhID0gbWRhdGEsIG1vZGVsPW1fcHVsbW9uYXJ5LCBvdXRjb21lID0gaW5jXzEwMGssIHBvcHVsYXRpb25fZGVub21pbmF0b3IgPSBwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwLCAKICAgICAgICAgICAgICAgICAgICBncm91cGluZ192YXIgPSB3YXJkLCB3YXJkLCByZV9mb3JtdWxhPSB+KDEgKyB5X251bSphY2ZfcGVyaW9kIHwgd2FyZCkpCiAgCmdnc2F2ZShoZXJlKCJmaWd1cmVzL3MzLnBuZyIpLCB3aWR0aD0xMiwgaGVpZ2h0PTEyKQoKYGBgCgpTdW1tYXJ5IG9mIGNoYW5nZSBpbiBub3RpZmljYXRpb25zIGF0IHdhcmQgbGV2ZWwKCmBgYHtyfQoKd2FyZF9jaGFuZ2UgPC0gc3VtbWFyaXNlX2NoYW5nZShtb2RlbF9kYXRhPW1kYXRhLCBtb2RlbD1tX3B1bG1vbmFyeSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcG9wdWxhdGlvbl9kZW5vbWluYXRvcj1wb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwLCBncm91cGluZ192YXI9d2FyZCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVfZm9ybXVsYSA9IH4oMSArIHlfbnVtKmFjZl9wZXJpb2QgfCB3YXJkKSkKCiN3YW50IHRvIGtlZXAgdGhlIHN1bW1hcnkgZXN0aW1hdGVzIGhlcmUKdG9rZWVwIDwtIGMoInBlYWtfc3VtbWFyeSIsICJsZXZlbF9zdW1tYXJ5IiwgInNsb3BlX3N1bW1hcnkiKQoKI3N1bW1hcnkgbWVhc3VyZXMgaW4gYSB0YWJsZQp3YXJkX2NoYW5nZSAlPiUKICBrZWVwKChuYW1lcyguKSAlaW4lIHRva2VlcCkpICU+JQogIGJpbmRfcm93cygpICU+JQogIG11dGF0ZShhY3Jvc3MoYyhlc3RpbWF0ZToudXBwZXIpLCBudW1iZXIsIGFjY3VyYWN5PTAuMDEpKSAlPiUKICBzZWxlY3QobWVhc3VyZSwgZXZlcnl0aGluZygpKSAlPiUKICBkYXRhdGFibGUoKQoKCiNwbG90IHRoZXNlIGluIGEgZmlndXJlCndhcmRfZWZmZWN0cyA8LSB3YXJkX2NoYW5nZSAlPiUKICBrZWVwKChuYW1lcyguKSAlaW4lIHRva2VlcCkpICU+JQogIGJpbmRfcm93cygpICU+JQogIGJpbmRfcm93cyhvdmVyYWxsX2NoYW5nZSRwZWFrX3N1bW1hcnkpICU+JQogIGJpbmRfcm93cyhvdmVyYWxsX2NoYW5nZSRsZXZlbF9zdW1tYXJ5KSAlPiUKICBiaW5kX3Jvd3Mob3ZlcmFsbF9jaGFuZ2Ukc2xvcGVfc3VtbWFyeSkgJT4lCiAgbXV0YXRlX2F0KC52YXJzID0gdmFycyhlc3RpbWF0ZToudXBwZXIpLCAKICAgICAgICAgICAgLmZ1bnMgPSBmdW5zKGFzLm51bWVyaWMpKSAlPiUKICBzZWxlY3QobWVhc3VyZSwgZXZlcnl0aGluZygpKSAlPiUKICBtdXRhdGUoZXN0aW1hdGUgPSBhcy5kb3VibGUoZXN0aW1hdGUpKSAlPiUKICBmdWxsX2pvaW4oZ2xhc2dvd193YXJkc18xOTUxKSAlPiUgCiAgbXV0YXRlKHdhcmQyID0gcGFzdGUwKHdhcmRfbnVtYmVyLCAiLiAiLCB3YXJkKSkgJT4lCiAgbXV0YXRlKHdhcmQyID0gY2FzZV93aGVuKGlzLm5hKHdhcmQpIH4gIk92ZXJhbGwiLAogICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiB3YXJkMikpICU+JQogIHN0X2FzX3NmKCkgCgojZnVuY3Rpb24gZm9yIHBsb3R0aW5nIGNob3JvcGxldGggbWFwcwpwbG90X3dhcmRfZWZmZWN0IDwtIGZ1bmN0aW9uKGRhdGEsIG1lYXN1cmUpewogIHt7ZGF0YX19ICU+JQogIGZpbHRlcihtZWFzdXJlID09IHt7bWVhc3VyZX19KSAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9zZihhZXMoZmlsbD1lc3RpbWF0ZSkpICsKICBnZW9tX3NmX2xhYmVsKGFlcyhsYWJlbCA9IHdhcmRfbnVtYmVyKSwgc2l6ZT0zLCBmaWxsPU5BLCBsYWJlbC5zaXplID0gTkEsIGNvbG91cj0iYmxhY2siKSArCiAgc2NhbGVfZmlsbF9ncmFkaWVudChoaWdoPSJsaWdodGJsdWUxIixsb3c9ImRhcmtibHVlIiwgbmFtZT0iIikgKwogIHRoZW1lX2dnZGlzdCgpICsKICB0aGVtZShwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXk3OCIsIGZpbGw9TkEpLAogICAgICAgIGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZT00NSwgaGp1c3Q9MSkpICsKICAgIGxhYnMoeD0iIiwgeT0iIikKfQoKI2Z1bmN0aW9uIGZvciBwbG90dGluZyBjYXRhcGlsbGVyIHBsb3RzCnBsb3Rfd2FyZF9jYXQgPC0gZnVuY3Rpb24oZGF0YSwgbWVhc3VyZSwgc2NhbGUpewoKICBwYWwgPC0gY29sb3JSYW1wUGFsZXR0ZShjKCdkYXJrYmx1ZScsJ2xpZ2h0Ymx1ZScpKQoKICB7e2RhdGF9fSAlPiUKICAgIGZpbHRlcihtZWFzdXJlPT17e21lYXN1cmV9fSkgJT4lCiAgICBtdXRhdGUobXlfcGFsZXR0ZSA9IGNhc2Vfd2hlbih3YXJkMj09Ik92ZXJhbGwiIH4gIiNDNjBDMzAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiBwYWwoMzYpW2FzLm51bWVyaWMoY3V0KC4kZXN0aW1hdGUsYnJlYWtzID0gMzYpKV0pKSAlPiUKICAgIGdncGxvdCgpICsKICAgIGdlb21fcG9pbnRyYW5nZShhZXMoeT1lc3RpbWF0ZSwgeW1pbj0ubG93ZXIsIHltYXg9LnVwcGVyLCAKICAgICAgICAgICAgICAgICAgICAgIHg9ZmN0X3Jlb3JkZXIod2FyZDIsIGVzdGltYXRlKSwgY29sb3VyPW15X3BhbGV0dGUpKSArCiAgICBjb29yZF9mbGlwKCkgKwogICAgc2NhbGVfY29sb3VyX2lkZW50aXR5KG5hbWU9IiIpICsKICAgIHNjYWxlX3lfY29udGludW91cygpICsKICAgIHRoZW1lX2dnZGlzdCgpICsKICAgIHRoZW1lKHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleTc4IiwgZmlsbD1OQSkpICsKICAgIGxhYnMoeCA9ICIiLAogICAgICAgICB5ID0gIlJlbGF0aXZlIHJhdGUgKDk1JSBDckkpIikKfQoKCgp3YXJkX3BlYWtfaSA8LSBwbG90X3dhcmRfZWZmZWN0KGRhdGEgPSB3YXJkX2VmZmVjdHMsIG1lYXN1cmUgPSAiUlIucGVhayIpCndhcmRfbGV2ZWxfaSA8LSBwbG90X3dhcmRfZWZmZWN0KGRhdGEgPSB3YXJkX2VmZmVjdHMsIG1lYXN1cmUgPSAiUlIubGV2ZWwiKQp3YXJkX3Nsb3BlX2kgPC0gcGxvdF93YXJkX2VmZmVjdChkYXRhID0gd2FyZF9lZmZlY3RzLCBtZWFzdXJlID0gIlJSLnNsb3BlIikKCndhcmRfcGVha19paSA8LSBwbG90X3dhcmRfY2F0KGRhdGEgPSB3YXJkX2VmZmVjdHMsIG1lYXN1cmUgPSAiUlIucGVhayIpCndhcmRfbGV2ZWxfaWkgPC0gcGxvdF93YXJkX2NhdChkYXRhID0gd2FyZF9lZmZlY3RzLCBtZWFzdXJlID0gIlJSLmxldmVsIikKd2FyZF9zbG9wZV9paSA8LSBwbG90X3dhcmRfY2F0KGRhdGEgPSB3YXJkX2VmZmVjdHMsIG1lYXN1cmUgPSAiUlIuc2xvcGUiKQoKczQgPC0gKHdhcmRfcGVha19pICsgd2FyZF9sZXZlbF9pICsgd2FyZF9zbG9wZV9pKSAvCiAgKHdhcmRfcGVha19paSArIHdhcmRfbGV2ZWxfaWkgKyB3YXJkX3Nsb3BlX2lpKQoKczRbWzFdXSA8LSBzNFtbMV1dICsgcGxvdF9sYXlvdXQodGFnX2xldmVsID0gJ25ldycpCnM0W1syXV0gPC0gczRbWzJdXSArIHBsb3RfbGF5b3V0KHRhZ19sZXZlbCA9ICduZXcnKQpzNCArIHBsb3RfYW5ub3RhdGlvbih0YWdfbGV2ZWxzID0gYygnQScsICcxJykpCgoKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvczQucG5nIiksIHdpZHRoID0gMTYsIGhlaWdodD0xMCkKCmBgYAoKQ2FsY3VsYXRlIHRoZSBjb3VudGVyZmFjdHVhbCBwZXIgd2FyZAoKYGBge3J9Cgp3YXJkX3B1bG1vbmFyeV9jb3VudGVyZiA8LSBjYWxjdWxhdGVfY291bnRlcmZhY3R1YWwobW9kZWxfZGF0YSA9IG1kYXRhLCBtb2RlbD1tX3B1bG1vbmFyeSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwb3B1bGF0aW9uX2Rlbm9taW5hdG9yID0gcG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwaW5nX3ZhciA9IHdhcmQsIHJlX2Zvcm11bGE9figxICsgeV9udW0qYWNmX3BlcmlvZCB8IHdhcmQpKQoKd2FyZF9wdWxtb25hcnlfY291bnRlcmYkY291bnRlcl9wb3N0ICU+JQogIG11dGF0ZShhY3Jvc3MoYyhjYXNlc19hdmVydGVkOmNhc2VzX2F2ZXJ0ZWQudXBwZXIsIGRpZmZfaW5jMTAwazpkaWZmX2luYzEwMGsudXBwZXIpLCBudW1iZXJfZm9ybWF0KGFjY3VyYWN5ID0gMC4xLCBiaWcubWFyayA9ICIsIikpKSAlPiUKICBtdXRhdGUoYWNyb3NzKGMocnJfaW5jMTAwazpycl9pbmMxMDBrLnVwcGVyKSwgbnVtYmVyX2Zvcm1hdChhY2N1cmFjeSA9IDAuMDEpKSkgJT4lCiAgbXV0YXRlKGFjcm9zcyhjKHBjdF9jaGFuZ2U6cGN0X2NoYW5nZS51cHBlciksIHBlcmNlbnQsIGFjY3VyYWN5PTAuMSkpICU+JQogIGRhdGF0YWJsZSgpCgoKYGBgCgpPdmVyYWxsIGNvdW50ZXJmYWN0dWFsIHBlciB3YXJkCgpgYGB7cn0KCndhcmRfcHVsbW9uYXJ5X2NvdW50ZXJmJGNvdW50ZXJfcG9zdF9vdmVyYWxsICU+JQogIG11dGF0ZShhY3Jvc3MoYyhjYXNlc19hdmVydGVkOmNhc2VzX2F2ZXJ0ZWQudXBwZXIpLCBudW1iZXJfZm9ybWF0KGFjY3VyYWN5ID0gMC4xLCBiaWcubWFyayA9ICIsIikpKSAlPiUKICBtdXRhdGUoYWNyb3NzKGMocGN0X2NoYW5nZTpwY3RfY2hhbmdlLnVwcGVyKSwgcGVyY2VudCwgYWNjdXJhY3k9MC4xKSkgJT4lCiAgZGF0YXRhYmxlKCkKCmBgYAoKCgojIyMgOC4gRXh0cmEtcHVsbW9uYXJ5IFRCIG5vdGlmaWNhdGlvbnMKCk5vdyB3ZSB3aWxsIG1vZGVsIHRoZSBleHRyYS1wdWxtb25hcnkgVEIgbm90aWZpY2F0aW9uIHJhdGUuIFN0cnVnZ2xpbmcgYSBiaXQgd2l0aCBuZWdhdGl2ZSBiaW5vbWlhbCBtb2RlbCwgc28gcmV2ZXJ0IHRvIFBvaXNzb24uCgojIyMjIDguMSBGaXQgdGhlIG1vZGVsCgpgYGB7cn0KCm1fZXh0cmFwdWxtb25hcnkgPC0gYnJtKAogIGNhc2VzIH4gMSArIHlfbnVtKmFjZl9wZXJpb2QgKyAoMSArIHlfbnVtKmFjZl9wZXJpb2QgfCB3YXJkKSArIG9mZnNldChsb2cocG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCkpLAogICAgICAgICAgICAgICAgICBkYXRhID0gbWRhdGFfZXh0cmFwdWxtb25hcnksCiAgICAgICAgICAgICAgICAgIGZhbWlseSA9IG5lZ2Jpbm9taWFsKCksCiAgICAgICAgICAgICAgICAgIHNlZWQgPSAxMjM0LAogICAgICAgICAgICAgICAgICBjaGFpbnMgPSA0LCBjb3JlcyA9IDQsCiAgICAgICAgICAgICAgICAgIHByaW9yID0gcHJpb3Iobm9ybWFsKDAsMTAwMCksIGNsYXNzID0gSW50ZXJjZXB0KSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgcHJpb3IoZ2FtbWEoMC4wMSwgMC4wMSksIGNsYXNzID0gc2hhcGUpICsKICAgICAgICAgICAgICAgICAgICAgICAgICBwcmlvcihub3JtYWwoMCwgMSksIGNsYXNzID0gYikgKwogICAgICAgICAgICAgICAgICAgICAgICAgIHByaW9yKGV4cG9uZW50aWFsKDEpLCBjbGFzcz1zZCkgKwogICAgICAgICAgICAgICAgICAgICAgICAgIHByaW9yKGxraigyKSwgY2xhc3M9Y29yKSkKCnN1bW1hcnkobV9leHRyYXB1bG1vbmFyeSkKcGxvdChtX2V4dHJhcHVsbW9uYXJ5KQpwcF9jaGVjayhtX2V4dHJhcHVsbW9uYXJ5LCB0eXBlPSdlY2RmX292ZXJsYXknKQoKYGBgCgojIyMjIDguMiBTdW1tYXJ5IG9mIGNoYW5nZQoKU3VtbWFyaXNlIGluIHBsb3QKCmBgYHtyfQpwbG90X2NvdW50ZXJmYWN0dWFsKG1vZGVsX2RhdGEgPSBvdmVyYWxsX3NjYWZmb2xkICU+JSBmaWx0ZXIoeWVhcjw9MTk2MSksIG1vZGVsPW1fZXh0cmFwdWxtb25hcnksIAogICAgICAgICAgICAgICAgICAgIHBvcHVsYXRpb25fZGVub21pbmF0b3IgPSBwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwLCBvdXRjb21lPWluY18xMDBrX2V4dHJhcHVsbW9uYXJ5LCByZV9mb3JtdWxhID0gTkEpCiAgCmdnc2F2ZShoZXJlKCJmaWd1cmVzL3M2LnBuZyIpLCB3aWR0aD0xMCkKCmBgYAoKU3VtbWFyaXNlIG51bWVyaWNhbGx5LgoKYGBge3J9CgpvdmVyYWxsX2NoYW5nZV9leHRyYXB1bG1vbmFyeSA8LSBzdW1tYXJpc2VfY2hhbmdlKG1vZGVsX2RhdGE9b3ZlcmFsbF9zY2FmZm9sZCwgbW9kZWw9bV9leHRyYXB1bG1vbmFyeSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcG9wdWxhdGlvbl9kZW5vbWluYXRvcj1wb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwLCBncm91cGluZ192YXI9TlVMTCwgcmVfZm9ybXVsYSA9IE5BKQoKI3dhbnQgdG8ga2VlcCB0aGUgc3VtbWFyeSBlc3RpbWF0ZXMgaGVyZQp0b2tlZXAgPC0gYygicGVha19zdW1tYXJ5IiwgImxldmVsX3N1bW1hcnkiLCAic2xvcGVfc3VtbWFyeSIpCgojc3VtbWFyeSBtZWFzdXJlcyBpbiBhIHRhYmxlCm92ZXJhbGxfY2hhbmdlX2V4dHJhcHVsbW9uYXJ5ICU+JQogIGtlZXAobmFtZXMoLikgJWluJSB0b2tlZXApICU+JQogIGJpbmRfcm93cygpICU+JQogIG11dGF0ZShhY3Jvc3MoYyhlc3RpbWF0ZToudXBwZXIpLCBudW1iZXIsIGFjY3VyYWN5PTAuMDEpKSAlPiUKICBzZWxlY3QobWVhc3VyZSwgZXZlcnl0aGluZygpKSAlPiUKICBkYXRhdGFibGUoKQoKYGBgCgojIyMjIDguMyBDb21wYXJlZCB0byBjb3VudGVyZmFjdHVhbAoKTnVtYmVycyBvZiBleHRyYS1wdWxtb25hcnkgVEIgY2FzZXMgYXZlcnRlZCBvdmVyYWxsLgoKYGBge3J9CgpvdmVyYWxsX2VwX2NvdW50ZXJmIDwtIGNhbGN1bGF0ZV9jb3VudGVyZmFjdHVhbChtb2RlbF9kYXRhID0gbWRhdGFfZXh0cmFwdWxtb25hcnksIG1vZGVsPW1fZXh0cmFwdWxtb25hcnksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBvcHVsYXRpb25fZGVub21pbmF0b3IgPSBwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwKQoKb3ZlcmFsbF9lcF9jb3VudGVyZiRjb3VudGVyX3Bvc3QgJT4lCiAgbXV0YXRlKGFjcm9zcyhjKGNhc2VzX2F2ZXJ0ZWQ6Y2FzZXNfYXZlcnRlZC51cHBlciwgZGlmZl9pbmMxMDBrOmRpZmZfaW5jMTAway51cHBlciksIG51bWJlcl9mb3JtYXQoYWNjdXJhY3kgPSAwLjEsIGJpZy5tYXJrID0gIiwiKSkpICU+JQogIG11dGF0ZShhY3Jvc3MoYyhycl9pbmMxMDBrOnJyX2luYzEwMGsudXBwZXIpLCBudW1iZXJfZm9ybWF0KGFjY3VyYWN5ID0gMC4wMSkpKSAlPiUKICBtdXRhdGUoYWNyb3NzKGMocGN0X2NoYW5nZTpwY3RfY2hhbmdlLnVwcGVyKSwgcGVyY2VudCwgYWNjdXJhY3k9MC4xKSkgJT4lCiAgZGF0YXRhYmxlKCkKCmBgYAoKVG90YWwgZXh0cmFwdWxtb25hcnkgVEIgY2FzZXMgYXZlcnRlZCBiZXR3ZWVuIDE5NTggYW5kIDE5NjMKCmBgYHtyfQoKb3ZlcmFsbF9lcF9jb3VudGVyZiRjb3VudGVyX3Bvc3Rfb3ZlcmFsbCAlPiUKICBtdXRhdGUoYWNyb3NzKGMoY2FzZXNfYXZlcnRlZDpjYXNlc19hdmVydGVkLnVwcGVyKSwgbnVtYmVyX2Zvcm1hdChhY2N1cmFjeSA9IDAuMSwgYmlnLm1hcmsgPSAiLCIpKSkgJT4lCiAgbXV0YXRlKGFjcm9zcyhjKHBjdF9jaGFuZ2U6cGN0X2NoYW5nZS51cHBlciksIHBlcmNlbnQsIGFjY3VyYWN5PTAuMSkpICU+JQogIGRhdGF0YWJsZSgpCgoKYGBgCgojIyMjIDguNCBXYXJkLWxldmVsIGV4dHJhLXB1bG1vbmFyeSBzdW1tYXJpZXMKCldhcmQtbGV2ZWwgZXh0cmEtcHVsbW9uYXJ5IGVzdGltYXRlcyBpbiBncmFwaGljYWwgZm9ybS4KCmBgYHtyfQoKcGxvdF9jb3VudGVyZmFjdHVhbChtb2RlbF9kYXRhID0gbWRhdGFfZXh0cmFwdWxtb25hcnksIG1vZGVsPW1fZXh0cmFwdWxtb25hcnksIG91dGNvbWUgPSBpbmNfMTAwaywgCiAgICAgICAgICAgICAgICAgICAgcG9wdWxhdGlvbl9kZW5vbWluYXRvciA9IHBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAsIGdyb3VwaW5nX3ZhciA9IHdhcmQscmVfZm9ybXVsYSA9fih5X251bSphY2ZfcGVyaW9kIHwgd2FyZCksIAogICAgICAgICAgICAgICAgICAgIHdhcmQpCiAgCmdnc2F2ZShoZXJlKCJmaWd1cmVzL3M0LnBuZyIpLCB3aWR0aD0xMCwgaGVpZ2h0PTEyKQoKYGBgCgpOdW1lcmljYWwgc3VtbWFyeS4KCmBgYHtyfQoKd2FyZF9jaGFuZ2VfZXh0cmFwdWxtb25hcnkgPC0gc3VtbWFyaXNlX2NoYW5nZShtb2RlbF9kYXRhID0gbWRhdGFfZXh0cmFwdWxtb25hcnksIG1vZGVsID0gbV9leHRyYXB1bG1vbmFyeSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcG9wdWxhdGlvbl9kZW5vbWluYXRvciA9IHBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAsIGdyb3VwaW5nX3Zhcj13YXJkLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlX2Zvcm11bGEgPSB+KHlfbnVtKmFjZl9wZXJpb2QgfCB3YXJkKSkgCgojd2FudCB0byBrZWVwIHRoZSBzdW1tYXJ5IGVzdGltYXRlcyBoZXJlCnRva2VlcCA8LSBjKCJwZWFrX3N1bW1hcnkiLCAibGV2ZWxfc3VtbWFyeSIsICJzbG9wZV9zdW1tYXJ5IikKCiNzdW1tYXJ5IG1lYXN1cmVzIGluIGEgdGFibGUKd2FyZF9jaGFuZ2VfZXh0cmFwdWxtb25hcnkgICU+JQogIGtlZXAobmFtZXMoLikgJWluJSB0b2tlZXApICU+JQogIGJpbmRfcm93cygpICU+JQogIG11dGF0ZShhY3Jvc3MoYyhlc3RpbWF0ZToudXBwZXIpLCBudW1iZXIsIGFjY3VyYWN5PTAuMDEpKSAlPiUKICBzZWxlY3QobWVhc3VyZSwgZXZlcnl0aGluZygpKSAlPiUKICBkYXRhdGFibGUoKQoKCgpgYGAKCgojIyMgOS4gQWdlLXNleCBtb2RlbAoKIyMjIyA5LjEgRkl0IHRoZSBtb2RlbAoKRml0IHRoZSBtb2RlbAoKKE5vdCByZXdyaXR0ZW4gdGhlIGZ1bmN0aW9ucyBmb3IgdGhpcyB5ZXQpCgpgYGB7cn0KCm1kYXRhX2FnZV9zZXggPC0gY2FzZXNfYnlfYWdlX3NleCAlPiUKICBmaWx0ZXIodGJfdHlwZT09IlB1bG1vbmFyeSIpICU+JQogIG11dGF0ZShhY2ZfcGVyaW9kID0gY2FzZV93aGVuKHllYXIgJWluJSBjKDE5NTA6MTk1NikgfiAiYS4gcHJlLWFjZiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeWVhciAlaW4lIGMoMTk1NykgfiAiYi4gYWNmIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ZWFyICVpbiUgYygxOTU4OjE5NjMpIH4gImMuIHBvc3QtYWNmIikpICU+JQogIG11dGF0ZSh5ZWFyMiA9IHllYXIrMC41KSAlPiUKICBncm91cF9ieShhZ2UsIHNleCkgJT4lCiAgbXV0YXRlKHlfbnVtID0gcm93X251bWJlcigpKSAlPiUKICB1bmdyb3VwKCkKCm1fYWdlX3NleCA8LSBicm0oCiAgY2FzZXMgfiB5X251bSArIChhY2ZfcGVyaW9kKSooYWdlKnNleCkgKyAoYWNmX3BlcmlvZDp5X251bSkqKGFnZSpzZXgpLAogICAgICAgICAgICAgICAgICBkYXRhID0gbWRhdGFfYWdlX3NleCwKICAgICAgICAgICAgICAgICAgZmFtaWx5ID0gbmVnYmlub21pYWwoKSwKICAgICAgICAgICAgICAgICAgc2VlZCA9IDEyMzQsCiAgICAgICAgICAgICAgICAgIGNoYWlucyA9IDQsIGNvcmVzID0gNCwgCiAgICAgICAgICAgICAgICAgIHByaW9yID0gcHJpb3Iobm9ybWFsKDAsMTAwMCksIGNsYXNzID0gSW50ZXJjZXB0KSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgcHJpb3IoZ2FtbWEoMC4wMSwgMC4wMSksIGNsYXNzID0gc2hhcGUpICsKICAgICAgICAgICAgICAgICAgICAgICAgICBwcmlvcihub3JtYWwoMCwgMSksIGNsYXNzID0gYikpCgpzdW1tYXJ5KG1fYWdlX3NleCkKcGxvdChtX2FnZV9zZXgpCnBwX2NoZWNrKG1fYWdlX3NleCwgdHlwZT0nZWNkZl9vdmVybGF5JykKCgpgYGAKClN1bW1hcmlzZSBwb3N0ZXJpb3IKCmBgYHtyfQoKI3Bvc3RlcmlvciBkcmF3cywgYW5kIHN1bW1hcmlzZQphZ2Vfc2V4X3N1bW1hcnkgPC0gbWRhdGFfYWdlX3NleCAlPiUKICBzZWxlY3QoeWVhciwgeWVhcjIsIHlfbnVtLCBhY2ZfcGVyaW9kLCBhZ2UsIHNleCkgJT4lCiAgYWRkX2VwcmVkX2RyYXdzKG1fYWdlX3NleCkgJT4lCiAgZ3JvdXBfYnkoeWVhcjIsIGFjZl9wZXJpb2QsIGFnZSwgc2V4KSAlPiUKICBtZWFuX3FpKCkgJT4lCiAgbXV0YXRlKGFjZl9wZXJpb2QgPSBjYXNlX3doZW4oYWNmX3BlcmlvZD09ImEuIHByZS1hY2YiIH4gIkJlZm9yZSBJbnRlcnZlbnRpb24iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFjZl9wZXJpb2Q9PSJjLiBwb3N0LWFjZiIgfiAiUG9zdCBJbnRlcnZlbnRpb24iKSkKCiNjcmVhdGUgdGhlIGNvdW50ZXJmYWN0dWFsIChubyBpbnRlcnZlbnRpb24pLCBhbmQgc3VtbWFyaXNlCmFnZV9zZXhfY291bnRlcmZhY3QgPC0gCiAgdGliYmxlKHllYXIgPSBtZGF0YV9hZ2Vfc2V4JHllYXIsCiAgICAgICAgIHllYXIyID0gbWRhdGFfYWdlX3NleCR5ZWFyMiwKICAgICAgICAgeV9udW0gPSBtZGF0YV9hZ2Vfc2V4JHlfbnVtLAogICAgICAgICBhZ2UgPSBtZGF0YV9hZ2Vfc2V4JGFnZSwKICAgICAgICAgc2V4ID0gbWRhdGFfYWdlX3NleCRzZXgsCiAgICAgICAgIGFjZl9wZXJpb2QgPSBmYWN0b3IoImEuIHByZS1hY2YiKSkgJT4lCiAgYWRkX2VwcmVkX2RyYXdzKG1fYWdlX3NleCkgJT4lCiAgZ3JvdXBfYnkoeWVhcjIsIGFjZl9wZXJpb2QsIGFnZSwgc2V4KSAlPiUKICBtZWFuX3FpKCkgJT4lCiAgbXV0YXRlKGFjZl9wZXJpb2QgPSBjYXNlX3doZW4oYWNmX3BlcmlvZD09ImEuIHByZS1hY2YiIH4gIkJlZm9yZSBJbnRlcnZlbnRpb24iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFjZl9wZXJpb2Q9PSJjLiBwb3N0LWFjZiIgfiAiUG9zdCBJbnRlcnZlbnRpb24iKSkgJT4lCiAgdW5ncm91cCgpICU+JQogIG11dGF0ZShhZ2UgPSBjYXNlX3doZW4oYWdlPT0iMDBfMDUiIH4gIjAgdG8gNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMDZfMTUiIH4gIjA2IHRvIDE1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIxNl8yNSIgfiAiMTYgdG8gMjV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjI2XzM1IiB+ICIyNiB0byAzNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMzZfNDUiIH4gIjM2IHRvIDQ1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSI0Nl81NSIgfiAiNDYgdG8gNTV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjU2XzY1IiB+ICI1NiB0byA2NXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iNjUrIiB+ICI2NSAmIHVwIHkiKSkgJT4lCiAgbXV0YXRlKHNleCA9IGNhc2Vfd2hlbihzZXg9PSAiTSIgfiAiTWFsZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBzZXg9PSAiRiIgfiAiRmVtYWxlIikpIAoKCgphZ2Vfc2V4X3N1bW1hcnkgJT4lCiAgdW5ncm91cCgpICU+JQogIG11dGF0ZShhZ2UgPSBjYXNlX3doZW4oYWdlPT0iMDBfMDUiIH4gIjAgdG8gNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMDZfMTUiIH4gIjA2IHRvIDE1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIxNl8yNSIgfiAiMTYgdG8gMjV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjI2XzM1IiB+ICIyNiB0byAzNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMzZfNDUiIH4gIjM2IHRvIDQ1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSI0Nl81NSIgfiAiNDYgdG8gNTV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjU2XzY1IiB+ICI1NiB0byA2NXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iNjUrIiB+ICI2NSAmIHVwIHkiKSkgJT4lCiAgbXV0YXRlKHNleCA9IGNhc2Vfd2hlbihzZXg9PSAiTSIgfiAiTWFsZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBzZXg9PSAiRiIgfiAiRmVtYWxlIikpICU+JQogIGdncGxvdCgpICsKICBnZW9tX3JpYmJvbihhZXMoeW1pbj0uZXByZWQubG93ZXIsIHltYXg9LmVwcmVkLnVwcGVyLCB4PXllYXIyLCBncm91cCA9IGFjZl9wZXJpb2QsIGZpbGw9YWNmX3BlcmlvZCksIGFscGhhPTAuNSkgKwogIGdlb21fcmliYm9uKGRhdGEgPSBhZ2Vfc2V4X2NvdW50ZXJmYWN0ICU+JSBmaWx0ZXIoeWVhcj49MTk1NiksIAogICAgICAgICAgICAgIGFlcyh5bWluPS5lcHJlZC5sb3dlciwgeW1heD0uZXByZWQudXBwZXIsIHg9eWVhcjIsIGZpbGw9IkNvdW50ZXJmYWN0dWFsIiksIGFscGhhPTAuNSkgKwogIGdlb21fbGluZShkYXRhID0gYWdlX3NleF9jb3VudGVyZmFjdCAlPiUgZmlsdGVyKHllYXI+PTE5NTYpLCAKICAgICAgICAgICAgICBhZXMoeT0uZXByZWQsIHg9eWVhcjIsIGNvbG91cj0iQ291bnRlcmZhY3R1YWwiKSkgKwogIGdlb21fbGluZShhZXMoeT0uZXByZWQsIHg9eWVhcjIsIGdyb3VwPWFjZl9wZXJpb2QsICBjb2xvdXI9YWNmX3BlcmlvZCkpICsKICBnZW9tX3BvaW50KGRhdGEgPSBtZGF0YV9hZ2Vfc2V4ICU+JQogIHVuZ3JvdXAoKSAlPiUKICBtdXRhdGUoYWdlID0gY2FzZV93aGVuKGFnZT09IjAwXzA1IiB+ICIwIHRvIDV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjA2XzE1IiB+ICIwNiB0byAxNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMTZfMjUiIH4gIjE2IHRvIDI1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIyNl8zNSIgfiAiMjYgdG8gMzV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjM2XzQ1IiB+ICIzNiB0byA0NXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iNDZfNTUiIH4gIjQ2IHRvIDU1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSI1Nl82NSIgfiAiNTYgdG8gNjV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjY1KyIgfiAiNjUgJiB1cCB5IikpICU+JQogIG11dGF0ZShzZXggPSBjYXNlX3doZW4oc2V4PT0gIk0iIH4gIk1hbGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgc2V4PT0gIkYiIH4gIkZlbWFsZSIpKSAsIGFlcyh5PWNhc2VzLCB4PXllYXIyLCBzaGFwZT1hY2ZfcGVyaW9kKSwgc2l6ZT0yKSArCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1hY2ZfZW5kKSwgbGluZXR5cGU9MykgKwogIGdnaDR4OjpmYWNldF9ncmlkMihhZ2V+c2V4LCBzY2FsZXMgPSAiZnJlZV95IiwgaW5kZXBlbmRlbnQgPSAieSIpICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscz1jb21tYSkgKwogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSB5ZWFyX2xhYmVscywKICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0geWVhcl9sYWJlbHMsCiAgICAgICAgICAgICAgICAgICAgIGd1aWRlID0gZ3VpZGVfYXhpcyhhbmdsZSA9IDkwKSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiNERTBEOTIiLCAiZ3JleTUwIiwgIiM0RDZDRkEiKSAsIG5hbWU9IiIpICsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoIiNERTBEOTIiLCAiZ3JleTUwIiwgIiM0RDZDRkEiKSAsIG5hbWU9IiIpICsKICBzY2FsZV9zaGFwZV9kaXNjcmV0ZShuYW1lPSIiKSArCiAgbGFicygKICAgIHggPSAiWWVhciIsCiAgICB5ID0gIkNhc2Ugbm90aWZpY2F0aW9ucyAobikiLAogICAgY2FwdGlvbiA9ICJNYXNzIG1pbmlhdHVyZSBYLXJheSBjYW1wYWlnbiBwZXJpb2QgYmV0d2VlbiBkYXNoZWQgbGluZXMgKDExdGggTWFyY2gtMTJ0aCBBcHJpbCAxOTU3KSIKICApICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXk3OCIsIGZpbGw9TkEpLAogICAgICAgIHRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MTQpLAogICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTE0KSwKICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTEyKSkgKwogIGd1aWRlcyhzaGFwZT0ibm9uZSIpCiAgCmdnc2F2ZShoZXJlKCJmaWd1cmVzL3M3LnBuZyIpLCBoZWlnaHQ9MTApCgpgYGAKCiMjIyMgOS4yIFN1bW1hcnkgb2YgaW1wYWN0IG9mIGludGVydmVudGlvbgoKKFRoaXMgYWxsIG5lZWRzIHRpZHlpbmcgdXAgYW5kIGNoZWNraW5nIC0gdG8gZG8hKQoKMS4gcGVyY2VudGFnZSBpbmNyZWFzZSBpbiBDTlIsIGZyb20gMTk1NiB0byAxOTU3IChpLmUuIGltbWVkaWF0ZSBBQ0YgZWZmZWN0KQoKYGBge3J9CgpuZCA8LSBtZGF0YV9hZ2Vfc2V4ICU+JQogIGZpbHRlcih5ZWFyICVpbiUgYygxOTU2OjE5NTcpKSAlPiUKICBzZWxlY3QoYWNmX3BlcmlvZCwgeV9udW0sIGFnZSwgc2V4KQoKCmFnZV9zZXhfaW1wYWN0X291dCA8LSAKICBhZGRfZXByZWRfZHJhd3MobV9hZ2Vfc2V4LAogICAgICAgICAgICAgICAgbmV3ZGF0YT1uZCkgJT4lCiAgdW5ncm91cCgpICU+JQogIHNlbGVjdChhY2ZfcGVyaW9kLCAuZXByZWQsIGFnZSwgc2V4KSAlPiUKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gYWNmX3BlcmlvZCwKICAgICAgICAgICAgICB2YWx1ZXNfZnJvbSA9IC5lcHJlZCwKICAgICAgICAgICAgICB2YWx1ZXNfZm4gPSBsaXN0KSAlPiUKICB1bm5lc3QoKSAlPiUKICByZW5hbWUocHJlX2VwcmVkID0gMywKICAgICAgICAgcG9zdF9lcHJlZCA9IDQpICU+JQogIG11dGF0ZShhY2ZfZGlmZiA9IHBvc3RfZXByZWQtcHJlX2VwcmVkLAogICAgICAgICBhY2ZfcnIgPSBwb3N0X2VwcmVkL3ByZV9lcHJlZCkgJT4lCiAgZ3JvdXBfYnkoYWdlLCBzZXgpICU+JQogIG1lYW5fcWkoYWNmX2RpZmYsIGFjZl9ycikgCgphZ2Vfc2V4X2ltcGFjdF9vdXQgJT4lCiAgbXV0YXRlX2lmKGlzLmRvdWJsZSwgfiBzY2FsZXM6Om51bWJlcih4ID0gLiwgYWNjdXJhY3kgPSAwLjAxLCBiaWcubWFyayA9ICIsIikpICU+JQogIGRhdGF0YWJsZSgpCiAgCmYzYSA8LSBhZ2Vfc2V4X2ltcGFjdF9vdXQgJT4lCiAgbXV0YXRlKHNleCA9IGNhc2Vfd2hlbihzZXg9PSJNIiB+ICJNYWxlIiwKICAgICAgICAgICAgICAgICAgICAgICAgIHNleD09IkYiIH4gIkZlbWFsZSIpKSAlPiUKICBtdXRhdGUoYWdlID0gY2FzZV93aGVuKGFnZT09IjAwXzA1IiB+ICIwIHRvIDV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjA2XzE1IiB+ICIwNiB0byAxNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMTZfMjUiIH4gIjE2IHRvIDI1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIyNl8zNSIgfiAiMjYgdG8gMzV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjM2XzQ1IiB+ICIzNiB0byA0NXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iNDZfNTUiIH4gIjQ2IHRvIDU1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSI1Nl82NSIgfiAiNTYgdG8gNjV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjY1KyIgfiAiNjUgJiB1cCB5IikpICU+JQogIGdncGxvdCgpICsKICBnZW9tX3BvaW50cmFuZ2UoYWVzKHk9YWNmX3JyLCB5bWluPWFjZl9yci5sb3dlciwgeW1heD1hY2ZfcnIudXBwZXIsIGdyb3VwPXNleCwgCiAgICAgICAgICAgICAgICAgICAgICB4PWFnZSwKICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IHNleCksCiAgICAgICAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjI1KSkgKwogIGdlb21faGxpbmUoYWVzKHlpbnRlcmNlcHQ9MSksIGxpbmV0eXBlPTIpICsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoInB1cnBsZSIsICJkYXJrb3JhbmdlIiksIG5hbWU9IiIpICsKICBsYWJzKHg9IiIsCiAgICAgICB5PSJSZWxhdGl2ZSBub3RpZmljYXRpb25zICg5NSUgVUkpXG5BQ0YgKDE5NTcpIHZzLiBCZWZvcmUgQUNGICgxOTU2KSIpICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5NzgiLCBmaWxsPU5BKSkKICAKICAKCmBgYAoKCjIuIENoYW5nZSBmcm9tIHByZS1BQ0YgcGVyaW9kICgxOTU2KSwgdG8gZmlyc3QgeWVhciBwb3N0LUFDRiAoMTk1OCkKCgpgYGB7cn0KCm5kIDwtIG1kYXRhX2FnZV9zZXggJT4lCiAgZmlsdGVyKHllYXIgJWluJSBjKDE5NTYsMTk1OCkpICU+JQogIHNlbGVjdChhY2ZfcGVyaW9kLCB5X251bSwgYWdlLCBzZXgpCgojRG8gaXQgd2l0aCBjYWxjdWxhdGluZyBpbmNpZGVuY2UsIHRoZW4gc3VtYW1yaXNpbmcuCmFnZV9zZXhfaW1wYWN0MiA8LWFkZF9lcHJlZF9kcmF3cyhtX2FnZV9zZXgsCiAgICAgICAgICAgICAgICBuZXdkYXRhPW5kKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgc2VsZWN0KGFjZl9wZXJpb2QsIC5lcHJlZCwgYWdlLCBzZXgpICU+JQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBhY2ZfcGVyaW9kLAogICAgICAgICAgICAgIHZhbHVlc19mcm9tID0gLmVwcmVkLAogICAgICAgICAgICAgIHZhbHVlc19mbiA9IGxpc3QpICU+JQogIHVubmVzdCgpICU+JQogIHJlbmFtZShwcmVfZXByZWQgPSAzLAogICAgICAgIHBvc3RfZXByZWQgPSA0KSAlPiUKICBtdXRhdGUoYWNmX2RpZmYgPSBwb3N0X2VwcmVkLXByZV9lcHJlZCwKICAgICAgICAgYWNmX3JyID0gcG9zdF9lcHJlZC9wcmVfZXByZWQpICU+JQogIGdyb3VwX2J5KGFnZSwgc2V4KSAlPiUKICBtZWFuX3FpKGFjZl9kaWZmLCBhY2ZfcnIpIAoKYWdlX3NleF9pbXBhY3QyICU+JQogIG11dGF0ZV9pZihpcy5kb3VibGUsIH4gc2NhbGVzOjpudW1iZXIoeCA9IC4sIGFjY3VyYWN5ID0gMC4wMSwgYmlnLm1hcmsgPSAiLCIpKSAlPiUKICBkYXRhdGFibGUoKQoKZjNiIDwtIGFnZV9zZXhfaW1wYWN0MiAlPiUgIAogIG11dGF0ZShzZXggPSBjYXNlX3doZW4oc2V4PT0iTSIgfiAiTWFsZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBzZXg9PSJGIiB+ICJGZW1hbGUiKSkgJT4lCiAgbXV0YXRlKGFnZSA9IGNhc2Vfd2hlbihhZ2U9PSIwMF8wNSIgfiAiMCB0byA1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIwNl8xNSIgfiAiMDYgdG8gMTV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjE2XzI1IiB+ICIxNiB0byAyNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMjZfMzUiIH4gIjI2IHRvIDM1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIzNl80NSIgfiAiMzYgdG8gNDV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjQ2XzU1IiB+ICI0NiB0byA1NXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iNTZfNjUiIH4gIjU2IHRvIDY1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSI2NSsiIH4gIjY1ICYgdXAgeSIpKSAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9wb2ludHJhbmdlKGFlcyh5PWFjZl9yciwgeW1pbj1hY2ZfcnIubG93ZXIsIHltYXg9YWNmX3JyLnVwcGVyLCBncm91cD1zZXgsIAogICAgICAgICAgICAgICAgICAgICAgeD1hZ2UsCiAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBzZXgpLAogICAgICAgICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC4yNSkpICsKICBnZW9tX2hsaW5lKGFlcyh5aW50ZXJjZXB0PTEpLCBsaW5ldHlwZT0yKSArCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCJwdXJwbGUiLCAiZGFya29yYW5nZSIpLCBuYW1lPSIiKSArCiAgbGFicyh4PSIiLAogICAgICAgeT0iUmVsYXRpdmUgbm90aWZpY2F0aW9ucyAoOTUlIFVJKVxuQUNGICgxOTU4KSB2cy4gQmVmb3JlIEFDRiAoMTk1NikiKSArCiAgdGhlbWVfZ2dkaXN0KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLAogICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleTc4IiwgZmlsbD1OQSkpCgoKYGBgCgozLiBDaGFuZ2UgaW4gc2xvcGUgKGkuZS4gZGlmZmVyZW5jZSBpbiBtZWFuIGFubnVhbCBjYXNlIG5vdGlmaWNhdGlvbiByYXRlIHByZS1JbnRlcnZlbnRpb24gdnMuIHBvc3QtaW50ZXJ2ZW50aW9uLCBieSB3YXJkKQoKYGBge3J9CgphZ2Vfc2V4X2ltcGFjdDMgPC0gbWRhdGFfYWdlX3NleCAlPiUKICBzZWxlY3QoeWVhciwgeWVhcjIsIHlfbnVtLCBhY2ZfcGVyaW9kLCBjYXNlcywgYWdlLCBzZXgpICU+JQogIGZpbHRlcih5ZWFyIT0xOTU3KSAlPiUKICBhZGRfZXByZWRfZHJhd3MobV9hZ2Vfc2V4KSAlPiUKICBncm91cF9ieSh5ZWFyLCBhZ2UsIHNleCwgYWNmX3BlcmlvZCkgJT4lCiAgbWVhbl9xaSguZXByZWQpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBtdXRhdGUobl95ZWFycyA9IGxlbmd0aCh5ZWFyKSwgLmJ5PWFjZl9wZXJpb2QpICU+JQogIHN1bW1hcmlzZShwY3RfY2hhbmdlX2VwcmVkX292ZXJhbGwgPSAoKChsYXN0KC5lcHJlZCkgLSBmaXJzdCguZXByZWQpKS9maXJzdCguZXByZWQpKSksCiAgICAgICAgICAgIHBjdF9jaGFuZ2VfbG93ZXJfb3ZlcmFsbCA9ICgoKGxhc3QoLmxvd2VyKSAtIGZpcnN0KC5sb3dlcikpL2ZpcnN0KC5sb3dlcikpKSwKICAgICAgICAgICAgcGN0X2NoYW5nZV91cHBlcl9vdmVyYWxsID0gKCgobGFzdCgudXBwZXIpIC0gZmlyc3QoLnVwcGVyKSkvZmlyc3QoLnVwcGVyKSkpLAogICAgCiAgICAgICAgICAgIHBjdF9jaGFuZ2VfZXByZWRfYW5udWFsID0gKCgobGFzdCguZXByZWQpIC0gZmlyc3QoLmVwcmVkKSkvZmlyc3QoLmVwcmVkKSkvbl95ZWFycyksCiAgICAgICAgICAgIHBjdF9jaGFuZ2VfbG93ZXJfYW5udWFsID0gKCgobGFzdCgubG93ZXIpIC0gZmlyc3QoLmxvd2VyKSkvZmlyc3QoLmxvd2VyKSkvbl95ZWFycyksCiAgICAgICAgICAgIHBjdF9jaGFuZ2VfdXBwZXJfYW5udWFsID0gKCgobGFzdCgudXBwZXIpIC0gZmlyc3QoLnVwcGVyKSkvZmlyc3QoLnVwcGVyKSkvbl95ZWFycyksCiAgICAgICAgICAgIC5ieSA9IGMoYWNmX3BlcmlvZCwgYWdlLCBzZXgpKSAlPiUKICBkaXN0aW5jdCgpCgoKYWdlX3NleF9pbXBhY3QzICU+JQogIG11dGF0ZV9pZihpcy5kb3VibGUsIHBlcmNlbnQpICU+JQogIGRhdGF0YWJsZSgpCgpmM2MgPC0gYWdlX3NleF9pbXBhY3QzICU+JQogIG11dGF0ZShzZXggPSBjYXNlX3doZW4oc2V4PT0iTSIgfiAiTWFsZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBzZXg9PSJGIiB+ICJGZW1hbGUiKSkgJT4lCiAgbXV0YXRlKGFnZSA9IGNhc2Vfd2hlbihhZ2U9PSIwMF8wNSIgfiAiMCB0byA1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIwNl8xNSIgfiAiMDYgdG8gMTV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjE2XzI1IiB+ICIxNiB0byAyNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMjZfMzUiIH4gIjI2IHRvIDM1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIzNl80NSIgfiAiMzYgdG8gNDV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjQ2XzU1IiB+ICI0NiB0byA1NXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iNTZfNjUiIH4gIjU2IHRvIDY1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSI2NSsiIH4gIjY1ICYgdXAgeSIpKSAlPiUKICBnZ3Bsb3QoKSArCiAgICBnZW9tX2hsaW5lKGFlcyh5aW50ZXJjZXB0PTApLCBsaW5ldHlwZT0yKSArCiAgICBnZW9tX3BvaW50cmFuZ2UoYWVzKHk9cGN0X2NoYW5nZV9lcHJlZF9hbm51YWwsIHltaW49cGN0X2NoYW5nZV9sb3dlcl9hbm51YWwsIHltYXg9cGN0X2NoYW5nZV91cHBlcl9hbm51YWwsIGdyb3VwPWFjZl9wZXJpb2QsIAogICAgICAgICAgICAgICAgICAgICAgeD1hZ2UsCiAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBhY2ZfcGVyaW9kKSwgc2l6ZT0wLjEpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID1wZXJjZW50KSArCiAgZmFjZXRfZ3JpZCgufnNleCkgKwogIGNvb3JkX2ZsaXAoKSArCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCIjREUwRDkyIiwgIiM0RDZDRkEiKSkgKwogIGxhYnMoeD0iIiwKICAgICAgIHk9Ik1lYW4gYW5udWFsIHJhdGUgb2YgY2hhbmdlIGluIGNhc2Ugbm90aWZpY2F0aW9uIHJhdGUgKDk1JSBVSSlcbiBCZWZvcmUgQUNGICgxOTUwLTE5NTYpIHZzLiBhZnRlciBBQ0YgKDE5NTgtMTk2MykiLAogICAgICAgY29sb3VyPSIiKSArCiAgdGhlbWVfZ2dkaXN0KCkgKwogIHRoZW1lKHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleTc4IiwgZmlsbD1OQSkpCgpmM2MKCmBgYAoKCiMjIyMgOS4zIENvbXBhcmVkIHRvIGNvdW50ZXJmYWN0dWFsCgpgYGB7cn0KCmNvdW50ZXJmYWN0X2FnZV9zZXggPC0KICAgICAgYWRkX2VwcmVkX2RyYXdzKG9iamVjdCA9IG1fYWdlX3NleCwKICAgICAgICAgICAgICAgICAgICAgIG5ld2RhdGEgPSBtZGF0YV9hZ2Vfc2V4ICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3QoeWVhciwgeWVhcjIsIHlfbnVtLCBhZ2UsIHNleCkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShhY2ZfcGVyaW9kID0gImEuIHByZS1hY2YiKSkgJT4lCiAgICAgIGZpbHRlcih5ZWFyPjE5NTcpICU+JQogICAgICBzZWxlY3QoeWVhciwgYWdlLCBzZXgsIC5kcmF3LCAuZXByZWRfY291bnRlcmYgPSAuZXByZWQpCiAgCiNDYWxjdWF0ZSBpbmNpZGVuY2UgcGVyIGRyYXcsIHRoZW4gc3VtbWFyaXNlLgogIHBvc3RfY2hhbmdlX2FnZV9zZXggPC0KICAgICAgYWRkX2VwcmVkX2RyYXdzKG9iamVjdCA9IG1fYWdlX3NleCwKICAgICAgICAgICAgICAgICAgICAgIG5ld2RhdGEgPSBtZGF0YV9hZ2Vfc2V4ICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3QoeWVhciwgeWVhcjIsIHlfbnVtLCBhZ2UsIHNleCwgYWNmX3BlcmlvZCkpICU+JQogICAgICBmaWx0ZXIoeWVhcj4xOTU3KSAlPiUKICAgICAgdW5ncm91cCgpICU+JQogICAgICBzZWxlY3QoeWVhciwgYWdlLCBzZXgsIC5kcmF3LCAuZXByZWQpIAogIAogICNmb3IgdGhlIG92ZXJhbGwgcGVyaW9kCmNvdW50ZXJmYWN0X292ZXJhbGxfYWdlX3NleCA8LQogICAgICBhZGRfZXByZWRfZHJhd3Mob2JqZWN0ID0gbV9hZ2Vfc2V4LAogICAgICAgICAgICAgICAgICAgICAgbmV3ZGF0YSA9IG1kYXRhX2FnZV9zZXggJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbGVjdCh5ZWFyLCB5ZWFyMiwgeV9udW0sIGFnZSwgc2V4KSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbXV0YXRlKGFjZl9wZXJpb2QgPSAiYS4gcHJlLWFjZiIpKSAlPiUKICAgICAgZmlsdGVyKHllYXI+MTk1NykgJT4lCiAgICAgIHNlbGVjdChhZ2UsIHNleCwgLmRyYXcsIC5lcHJlZCkgICU+JQogICAgICBncm91cF9ieShhZ2UsIHNleCwgLmRyYXcpICU+JQogICAgICBzdW1tYXJpc2UoLmVwcmVkX2NvdW50ZXJmID0gc3VtKC5lcHJlZCkpICU+JQogICAgICBtdXRhdGUoeWVhciA9ICJPdmVyYWxsICgxOTU4LTE5NjMpIikKICAKICAjQ2FsY3VhdGUgaW5jaWRlbmNlIHBlciBkcmF3LCB0aGVuIHN1bW1hcmlzZS4KICBwb3N0X2NoYW5nZV9vdmVyYWxsX2FnZV9zZXggPC0KICAgICAgYWRkX2VwcmVkX2RyYXdzKG9iamVjdCA9IG1fYWdlX3NleCwKICAgICAgICAgICAgICAgICAgICAgIG5ld2RhdGEgPSBtZGF0YV9hZ2Vfc2V4ICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3QoeWVhciwgeWVhcjIsIHlfbnVtLCBhZ2UsIHNleCwgYWNmX3BlcmlvZCkpICU+JQogICAgICBmaWx0ZXIoeWVhcj4xOTU3KSAlPiUKICAgICAgc2VsZWN0KGFnZSwgc2V4LCAuZHJhdywgLmVwcmVkKSAlPiUKICAgICAgZ3JvdXBfYnkoLmRyYXcsIGFnZSwgc2V4KSAlPiUKICAgICAgc3VtbWFyaXNlKC5lcHJlZCA9IHN1bSguZXByZWQpKSAKICAKICAKCmxlZnRfam9pbihjb3VudGVyZmFjdF9hZ2Vfc2V4LCBwb3N0X2NoYW5nZV9hZ2Vfc2V4KSAlPiUKICAgIG11dGF0ZShjYXNlc19hdmVydGVkID0gLmVwcmVkX2NvdW50ZXJmLS5lcHJlZCwKICAgICAgICAgICBwY3RfY2hhbmdlID0gKC5lcHJlZCAtIC5lcHJlZF9jb3VudGVyZikvLmVwcmVkX2NvdW50ZXJmKSAlPiUKICAgIGdyb3VwX2J5KHllYXIsIGFnZSwgc2V4KSAlPiUKICAgIG1lYW5fcWkoY2FzZXNfYXZlcnRlZCwgcGN0X2NoYW5nZSkgJT4lCiAgICB1bmdyb3VwKCkgJT4lCiAgZGF0YXRhYmxlKCkKCmNvdW50ZXJfcG9zdF9vdmVyYWxsX2FnZV9zZXggPC0KICBsZWZ0X2pvaW4oY291bnRlcmZhY3Rfb3ZlcmFsbF9hZ2Vfc2V4LCBwb3N0X2NoYW5nZV9vdmVyYWxsX2FnZV9zZXgpICU+JQogICAgbXV0YXRlKGNhc2VzX2F2ZXJ0ZWQgPSAuZXByZWRfY291bnRlcmYtLmVwcmVkLAogICAgICAgICAgIHBjdF9jaGFuZ2UgPSAoLmVwcmVkIC0gLmVwcmVkX2NvdW50ZXJmKS8uZXByZWRfY291bnRlcmYpICU+JQogICAgZ3JvdXBfYnkoYWdlLCBzZXgpICU+JQogICAgbWVhbl9xaShjYXNlc19hdmVydGVkLCBwY3RfY2hhbmdlKSAlPiUKICAgIHVuZ3JvdXAoKSAlPiUKICAgIG11dGF0ZSh5ZWFyID0gIk92ZXJhbGwgKDE5NTgtMTk2MykiKSAKCgpgYGAKCgpgYGB7cn0KCmFnZV9zZXhfdHh0IDwtIGNvdW50ZXJfcG9zdF9vdmVyYWxsX2FnZV9zZXggJT4lCiAgbXV0YXRlKGFjcm9zcyhjKGNhc2VzX2F2ZXJ0ZWQ6Y2FzZXNfYXZlcnRlZC51cHBlciksIG51bWJlcl9mb3JtYXQoYWNjdXJhY3kgPSAwLjEsIGJpZy5tYXJrID0gIiwiKSkpICU+JQogIG11dGF0ZShhY3Jvc3MoYyhwY3RfY2hhbmdlOnBjdF9jaGFuZ2UudXBwZXIpLCBwZXJjZW50LCBhY2N1cmFjeT0wLjEpKSAlPiUKICB0cmFuc211dGUoeWVhciA9IGFzLmNoYXJhY3Rlcih5ZWFyKSwKICAgICAgICAgICAgc2V4ID0gc2V4LAogICAgICAgICAgICBhZ2UgPSBhZ2UsCiAgICAgICAgICAgIGNhc2VzX2F2ZXJ0ZWQgPSBnbHVlOjpnbHVlKCJ7Y2FzZXNfYXZlcnRlZH1cbih7Y2FzZXNfYXZlcnRlZC5sb3dlcn0gdG8ge2Nhc2VzX2F2ZXJ0ZWQudXBwZXJ9KSIpLAogICAgICAgICAgICBwY3RfY2hhbmdlID0gZ2x1ZTo6Z2x1ZSgie3BjdF9jaGFuZ2V9XG4oe3BjdF9jaGFuZ2UubG93ZXJ9IHRvIHtwY3RfY2hhbmdlLnVwcGVyfSkiKSkKCgphZ2Vfc2V4X3R4dCAlPiUgZGF0YXRhYmxlKCkKCgpgYGAKCmBgYHtyfQoKZjNkIDwtIGNvdW50ZXJfcG9zdF9vdmVyYWxsX2FnZV9zZXggJT4lIAogIG11dGF0ZShzZXggPSBjYXNlX3doZW4oc2V4PT0iTSIgfiAiTWFsZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBzZXg9PSJGIiB+ICJGZW1hbGUiKSkgJT4lCiAgbXV0YXRlKGFnZSA9IGNhc2Vfd2hlbihhZ2U9PSIwMF8wNSIgfiAiMCB0byA1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIwNl8xNSIgfiAiMDYgdG8gMTV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjE2XzI1IiB+ICIxNiB0byAyNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMjZfMzUiIH4gIjI2IHRvIDM1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIzNl80NSIgfiAiMzYgdG8gNDV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjQ2XzU1IiB+ICI0NiB0byA1NXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iNTZfNjUiIH4gIjU2IHRvIDY1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSI2NSsiIH4gIjY1ICYgdXAgeSIpKSAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9wb2ludHJhbmdlKGFlcyh4ID0gYWdlLCB5PWNhc2VzX2F2ZXJ0ZWQsIHltaW49Y2FzZXNfYXZlcnRlZC5sb3dlciwgeW1heD1jYXNlc19hdmVydGVkLnVwcGVyLCBjb2xvdXI9c2V4KSkgKyAKICBmYWNldF9ncmlkKC5+c2V4KSArCiAgY29vcmRfZmxpcCgpICsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoInB1cnBsZSIsICJkYXJrb3JhbmdlIiksIG5hbWU9IiIpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gY29tbWEpICsKICBsYWJzKHg9IiIsCiAgICAgICB5PSJOdW1iZXIgKDk1JSBVSSkgb2YgVEIgY2FzZXMgYXZlcnRlZCAoMTk1OC0xOTYzKSIsCiAgICAgICBjb2xvdXI9IiIpICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgdGhlbWUocGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5NzgiLCBmaWxsPU5BKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCgpmM2QKYGBgCgoKCgpKb2luIHRvZ2V0aGVyIGZvciBGaWd1cmUgMi4KCgpgYGB7cn0KCihmM2EgKyBmM2IpIC8gKGYzYyArIGYzZCkgKyBwbG90X2Fubm90YXRpb24odGFnX2xldmVscyA9ICJBIikKCmdnc2F2ZShoZXJlKCJmaWd1cmVzL2YzLnBuZyIpLCB3aWR0aCA9IDEyKQoKCmBgYAptZGF0YV9hZ2Vfc2V4